config.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 }