URI:
       tconfig.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
       ---
       tconfig.c (9474B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <bio.h>
            4 #include <thread.h>
            5 #include <sunrpc.h>
            6 #include <nfs3.h>
            7 #include <diskfs.h>
            8 #include <venti.h>
            9 #include <libsec.h>
           10 
           11 #undef stime
           12 #define stime configstime        /* sometimes in <time.h> */
           13 typedef struct Entry Entry;
           14 struct Entry
           15 {
           16         Entry *parent;
           17         Entry *nextdir;
           18         Entry *nexthash;
           19         Entry *kids;
           20         int isfsys;
           21         Fsys *fsys;
           22         uchar score[VtScoreSize];        /* of fsys */
           23         char *name;
           24         uchar sha1[VtScoreSize];        /* of path to this entry */
           25         ulong time;
           26 };
           27 
           28 typedef struct Config Config;
           29 struct Config
           30 {
           31         VtCache *vcache;
           32         Entry *root;
           33         Entry *hash[1024];
           34         Qid qid;
           35 };
           36 
           37 Config *config;
           38 static        ulong         mtime;        /* mod time */
           39 static        ulong         stime;        /* sync time */
           40 static        char*        configfile;
           41 
           42 static int addpath(Config*, char*, uchar[VtScoreSize], ulong);
           43 Fsys fsysconfig;
           44 
           45 static void
           46 freeconfig(Config *c)
           47 {
           48         Entry *next, *e;
           49         int i;
           50 
           51         for(i=0; i<nelem(c->hash); i++){
           52                 for(e=c->hash[i]; e; e=next){
           53                         next = e->nexthash;
           54                         free(e);
           55                 }
           56         }
           57         free(c);
           58 }
           59 
           60 static int
           61 namehash(uchar *s)
           62 {
           63         return (s[0]<<2)|(s[1]>>6);
           64 }
           65 
           66 static Entry*
           67 entrybyhandle(Nfs3Handle *h)
           68 {
           69         int hh;
           70         Entry *e;
           71 
           72         hh = namehash(h->h);
           73         for(e=config->hash[hh]; e; e=e->nexthash)
           74                 if(memcmp(e->sha1, h->h, VtScoreSize) == 0)
           75                         return e;
           76         return nil;
           77 }
           78 
           79 static Config*
           80 readconfigfile(char *name, VtCache *vcache)
           81 {
           82         char *p, *pref, *f[10];
           83         int ok;
           84         Config *c;
           85         uchar score[VtScoreSize];
           86         int h, nf, line;
           87         Biobuf *b;
           88         Dir *dir;
           89 
           90         configfile = vtstrdup(name);
           91 
           92         if((dir = dirstat(name)) == nil)
           93                 return nil;
           94 
           95         if((b = Bopen(name, OREAD)) == nil){
           96                 free(dir);
           97                 return nil;
           98         }
           99 
          100         line = 0;
          101         ok = 1;
          102         c = emalloc(sizeof(Config));
          103         c->vcache = vcache;
          104         c->qid = dir->qid;
          105         free(dir);
          106         c->root = emalloc(sizeof(Entry));
          107         c->root->name = "/";
          108         c->root->parent = c->root;
          109         sha1((uchar*)"/", 1, c->root->sha1, nil);
          110         h = namehash(c->root->sha1);
          111         c->hash[h] = c->root;
          112 
          113         for(; (p = Brdstr(b, '\n', 1)) != nil; free(p)){
          114                 line++;
          115                 if(p[0] == '#')
          116                         continue;
          117                 nf = tokenize(p, f, nelem(f));
          118                 if(nf != 3){
          119                         fprint(2, "%s:%d: syntax error\n", name, line);
          120                         /* ok = 0; */
          121                         continue;
          122                 }
          123                 if(vtparsescore(f[1], &pref, score) < 0){
          124                         fprint(2, "%s:%d: bad score '%s'\n", name, line, f[1]);
          125                         /* ok = 0; */
          126                         continue;
          127                 }
          128                 if(f[0][0] != '/'){
          129                         fprint(2, "%s:%d: unrooted path '%s'\n", name, line, f[0]);
          130                         /* ok = 0; */
          131                         continue;
          132                 }
          133                 if(addpath(c, f[0], score, strtoul(f[2], 0, 0)) < 0){
          134                         fprint(2, "%s:%d: %s: %r\n", name, line, f[0]);
          135                         /* ok = 0; */
          136                         continue;
          137                 }
          138         }
          139         Bterm(b);
          140 
          141         if(!ok){
          142                 freeconfig(c);
          143                 return nil;
          144         }
          145 
          146         return c;
          147 }
          148 
          149 static void
          150 refreshconfig(void)
          151 {
          152         ulong now;
          153         Config *c, *old;
          154         Dir *d;
          155 
          156         now = time(0);
          157         if(now - stime < 60)
          158                 return;
          159         if((d = dirstat(configfile)) == nil)
          160                 return;
          161         if(d->mtime == mtime){
          162                 free(d);
          163                 stime = now;
          164                 return;
          165         }
          166 
          167         c = readconfigfile(configfile, config->vcache);
          168         if(c == nil){
          169                 free(d);
          170                 return;
          171         }
          172 
          173         old = config;
          174         config = c;
          175         stime = now;
          176         mtime = d->mtime;
          177         free(d);
          178         freeconfig(old);
          179 }
          180 
          181 static Entry*
          182 entrylookup(Entry *e, char *p, int np)
          183 {
          184         for(e=e->kids; e; e=e->nextdir)
          185                 if(strlen(e->name) == np && memcmp(e->name, p, np) == 0)
          186                         return e;
          187         return nil;
          188 }
          189 
          190 static Entry*
          191 walkpath(Config *c, char *name)
          192 {
          193         Entry *e, *ee;
          194         char *p, *nextp;
          195         int h;
          196 
          197         e = c->root;
          198         p = name;
          199         for(; *p; p=nextp){
          200                 assert(*p == '/');
          201                 p++;
          202                 nextp = strchr(p, '/');
          203                 if(nextp == nil)
          204                         nextp = p+strlen(p);
          205                 if(e->fsys){
          206                         werrstr("%.*s is already a mount point", utfnlen(name, nextp-name), name);
          207                         return nil;
          208                 }
          209                 if((ee = entrylookup(e, p, nextp-p)) == nil){
          210                         ee = emalloc(sizeof(Entry)+(nextp-p)+1);
          211                         ee->parent = e;
          212                         ee->nextdir = e->kids;
          213                         e->kids = ee;
          214                         ee->name = (char*)&ee[1];
          215                         memmove(ee->name, p, nextp-p);
          216                         ee->name[nextp-p] = 0;
          217                         sha1((uchar*)name, nextp-name, ee->sha1, nil);
          218                         h = namehash(ee->sha1);
          219                         ee->nexthash = c->hash[h];
          220                         c->hash[h] = ee;
          221                 }
          222                 e = ee;
          223         }
          224         if(e->kids){
          225                 werrstr("%s already has children; cannot be mount point", name);
          226                 return nil;
          227         }
          228         return e;
          229 }
          230 
          231 static int
          232 addpath(Config *c, char *name, uchar score[VtScoreSize], ulong time)
          233 {
          234         Entry *e;
          235 
          236         e = walkpath(c, name);
          237         if(e == nil)
          238                 return -1;
          239         e->isfsys = 1;
          240         e->time = time;
          241         memmove(e->score, score, VtScoreSize);
          242         return 0;
          243 }
          244 
          245 static void
          246 mkhandle(Nfs3Handle *h, Entry *e)
          247 {
          248         memmove(h->h, e->sha1, VtScoreSize);
          249         h->len = VtScoreSize;
          250 }
          251 
          252 Nfs3Status
          253 handleparse(Nfs3Handle *h, Fsys **pfsys, Nfs3Handle *nh, int isgetattr)
          254 {
          255         int hh;
          256         Entry *e;
          257         Disk *disk;
          258         Fsys *fsys;
          259 
          260         refreshconfig();
          261 
          262         if(h->len < VtScoreSize)
          263                 return Nfs3ErrBadHandle;
          264 
          265         hh = namehash(h->h);
          266         for(e=config->hash[hh]; e; e=e->nexthash)
          267                 if(memcmp(e->sha1, h->h, VtScoreSize) == 0)
          268                         break;
          269         if(e == nil)
          270                 return Nfs3ErrBadHandle;
          271 
          272         if(e->isfsys == 1 && e->fsys == nil && (h->len != VtScoreSize || !isgetattr)){
          273                 if((disk = diskopenventi(config->vcache, e->score)) == nil){
          274                         fprint(2, "cannot open disk %V: %r\n", e->score);
          275                         return Nfs3ErrIo;
          276                 }
          277                 if((fsys = fsysopen(disk)) == nil){
          278                         fprint(2, "cannot open fsys on %V: %r\n", e->score);
          279                         diskclose(disk);
          280                         return Nfs3ErrIo;
          281                 }
          282                 e->fsys = fsys;
          283         }
          284 
          285         if(e->fsys == nil || (isgetattr && h->len == VtScoreSize)){
          286                 if(h->len != VtScoreSize)
          287                         return Nfs3ErrBadHandle;
          288                 *pfsys = &fsysconfig;
          289                 *nh = *h;
          290                 return Nfs3Ok;
          291         }
          292         *pfsys = e->fsys;
          293         if(h->len == VtScoreSize)
          294                 return fsysroot(*pfsys, nh);
          295         nh->len = h->len - VtScoreSize;
          296         memmove(nh->h, h->h+VtScoreSize, nh->len);
          297         return Nfs3Ok;
          298 }
          299 
          300 void
          301 handleunparse(Fsys *fsys, Nfs3Handle *h, Nfs3Handle *nh, int dotdot)
          302 {
          303         Entry *e;
          304         int hh;
          305 
          306         refreshconfig();
          307 
          308         if(fsys == &fsysconfig)
          309                 return;
          310 
          311         if(dotdot && nh->len == h->len - VtScoreSize
          312         && memcmp(h->h+VtScoreSize, nh->h, nh->len) == 0){
          313                 /* walked .. but didn't go anywhere: must be at root */
          314                 hh = namehash(h->h);
          315                 for(e=config->hash[hh]; e; e=e->nexthash)
          316                         if(memcmp(e->sha1, h->h, VtScoreSize) == 0)
          317                                 break;
          318                 if(e == nil)
          319                         return;        /* cannot happen */
          320 
          321                 /* walk .. */
          322                 e = e->parent;
          323                 nh->len = VtScoreSize;
          324                 memmove(nh->h, e->sha1, VtScoreSize);
          325                 return;
          326         }
          327 
          328         /* otherwise just insert the same prefix */
          329         memmove(nh->h+VtScoreSize, nh->h, VtScoreSize);
          330         nh->len += VtScoreSize;
          331         memmove(nh->h, h->h, VtScoreSize);
          332 }
          333 
          334 Nfs3Status
          335 fsysconfigroot(Fsys *fsys, Nfs3Handle *h)
          336 {
          337         USED(fsys);
          338 
          339         mkhandle(h, config->root);
          340         return Nfs3Ok;
          341 }
          342 
          343 Nfs3Status
          344 fsysconfiggetattr(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, Nfs3Attr *attr)
          345 {
          346         Entry *e;
          347 
          348         USED(fsys);
          349         USED(au);
          350 
          351         if(h->len != VtScoreSize)
          352                 return Nfs3ErrBadHandle;
          353 
          354         e = entrybyhandle(h);
          355         if(e == nil)
          356                 return Nfs3ErrNoEnt;
          357 
          358         memset(attr, 0, sizeof *attr);
          359         attr->type = Nfs3FileDir;
          360         attr->mode = 0555;
          361         attr->nlink = 2;
          362         attr->size = 1024;
          363         attr->fileid = *(u64int*)h->h;
          364         attr->atime.sec = e->time;
          365         attr->mtime.sec = e->time;
          366         attr->ctime.sec = e->time;
          367         return Nfs3Ok;
          368 }
          369 
          370 Nfs3Status
          371 fsysconfigaccess(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr)
          372 {
          373         want &= Nfs3AccessRead|Nfs3AccessLookup|Nfs3AccessExecute;
          374         *got = want;
          375         return fsysconfiggetattr(fsys, au, h, attr);
          376 }
          377 
          378 Nfs3Status
          379 fsysconfiglookup(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char *name, Nfs3Handle *nh)
          380 {
          381         Entry *e;
          382 
          383         USED(fsys);
          384         USED(au);
          385 
          386         if(h->len != VtScoreSize)
          387                 return Nfs3ErrBadHandle;
          388 
          389         e = entrybyhandle(h);
          390         if(e == nil)
          391                 return Nfs3ErrNoEnt;
          392 
          393         if(strcmp(name, "..") == 0)
          394                 e = e->parent;
          395         else if(strcmp(name, ".") == 0){
          396                 /* nothing */
          397         }else{
          398                 if((e = entrylookup(e, name, strlen(name))) == nil)
          399                         return Nfs3ErrNoEnt;
          400         }
          401 
          402         mkhandle(nh, e);
          403         return Nfs3Ok;
          404 }
          405 
          406 Nfs3Status
          407 fsysconfigreadlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link)
          408 {
          409         USED(h);
          410         USED(fsys);
          411         USED(au);
          412 
          413         *link = 0;
          414         return Nfs3ErrNotSupp;
          415 }
          416 
          417 Nfs3Status
          418 fsysconfigreadfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int offset, uchar **pdata, u32int *pcount, u1int *peof)
          419 {
          420         USED(fsys);
          421         USED(h);
          422         USED(count);
          423         USED(offset);
          424         USED(pdata);
          425         USED(pcount);
          426         USED(peof);
          427         USED(au);
          428 
          429         return Nfs3ErrNotSupp;
          430 }
          431 
          432 Nfs3Status
          433 fsysconfigreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int cookie, uchar **pdata, u32int *pcount, u1int *peof)
          434 {
          435         uchar *data, *p, *ep, *np;
          436         u64int c;
          437         Entry *e;
          438         Nfs3Entry ne;
          439 
          440         USED(fsys);
          441         USED(au);
          442 
          443         if(h->len != VtScoreSize)
          444                 return Nfs3ErrBadHandle;
          445 
          446         e = entrybyhandle(h);
          447         if(e == nil)
          448                 return Nfs3ErrNoEnt;
          449 
          450         e = e->kids;
          451         c = cookie;
          452         for(; c && e; c--)
          453                 e = e->nextdir;
          454         if(e == nil){
          455                 *pdata = 0;
          456                 *pcount = 0;
          457                 *peof = 1;
          458                 return Nfs3Ok;
          459         }
          460 
          461         data = emalloc(count);
          462         p = data;
          463         ep = data+count;
          464         while(e && p < ep){
          465                 ne.name = e->name;
          466                 ne.namelen = strlen(e->name);
          467                 ne.cookie = ++cookie;
          468                 ne.fileid = *(u64int*)e->sha1;
          469                 if(nfs3entrypack(p, ep, &np, &ne) < 0)
          470                         break;
          471                 p = np;
          472                 e = e->nextdir;
          473         }
          474         *pdata = data;
          475         *pcount = p - data;
          476         *peof = 0;
          477         return Nfs3Ok;
          478 }
          479 
          480 void
          481 fsysconfigclose(Fsys *fsys)
          482 {
          483         USED(fsys);
          484 }
          485 
          486 int
          487 readconfig(char *name, VtCache *vcache, Nfs3Handle *h)
          488 {
          489         Config *c;
          490         Dir *d;
          491 
          492         if((d = dirstat(name)) == nil)
          493                 return -1;
          494 
          495         c = readconfigfile(name, vcache);
          496         if(c == nil){
          497                 free(d);
          498                 return -1;
          499         }
          500 
          501         config = c;
          502         mtime = d->mtime;
          503         stime = time(0);
          504         free(d);
          505 
          506         mkhandle(h, c->root);
          507         fsysconfig._lookup = fsysconfiglookup;
          508         fsysconfig._access = fsysconfigaccess;
          509         fsysconfig._getattr = fsysconfiggetattr;
          510         fsysconfig._readdir = fsysconfigreaddir;
          511         fsysconfig._readfile = fsysconfigreadfile;
          512         fsysconfig._readlink = fsysconfigreadlink;
          513         fsysconfig._root = fsysconfigroot;
          514         fsysconfig._close = fsysconfigclose;
          515         return 0;
          516 }