plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

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 }