plan9port

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

fs.c (8928B)


      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 int *loginuse = &inuse[5];
    264 static void
    265 fsopen(Req *r)
    266 {
    267 	int i, *inusep, perm;
    268 	static int need[4] = { 4, 2, 6, 1 };
    269 	Conv *c;
    270 
    271 	inusep = nil;
    272 	perm = 5;	/* directory */
    273 	for(i=0; i<nelem(dirtab); i++)
    274 		if(dirtab[i].qidpath == r->fid->qid.path){
    275 			if(dirtab[i].perm & DMEXCL)
    276 				inusep = &inuse[i];
    277 			if(strcmp(r->fid->uid, owner) == 0)
    278 				perm = dirtab[i].perm>>6;
    279 			else
    280 				perm = dirtab[i].perm;
    281 			break;
    282 		}
    283 
    284 	if((r->ifcall.mode&~(OMASK|OTRUNC))
    285 	|| (need[r->ifcall.mode&3] & ~perm)){
    286 		respond(r, "permission denied");
    287 		return;
    288 	}
    289 
    290 	if(inusep){
    291 		if(*inusep){
    292 			respond(r, "file in use");
    293 			return;
    294 		}
    295 		*inusep = 1;
    296 	}
    297 
    298 	if(r->fid->qid.path == Qrpc){
    299 		if((c = convalloc(r->fid->uid)) == nil){
    300 			char e[ERRMAX];
    301 
    302 			rerrstr(e, sizeof e);
    303 			respond(r, e);
    304 			return;
    305 		}
    306 		c->kickreply = fskickreply;
    307 		r->fid->aux = c;
    308 	}
    309 
    310 	respond(r, nil);
    311 }
    312 
    313 static void
    314 fsread(Req *r)
    315 {
    316 	Conv *c;
    317 
    318 	switch((int)r->fid->qid.path){
    319 	default:
    320 		respond(r, "fsread: cannot happen");
    321 		break;
    322 	case Qroot:
    323 		dirread9p(r, rootdirgen, nil);
    324 		respond(r, nil);
    325 		break;
    326 	case Qfactotum:
    327 		dirread9p(r, fsdirgen, nil);
    328 		respond(r, nil);
    329 		break;
    330 	case Qrpc:
    331 		c = r->fid->aux;
    332 		if(c->rpc.op == RpcUnknown){
    333 			respond(r, "no rpc pending");
    334 			break;
    335 		}
    336 		if(c->req){
    337 			respond(r, "read already pending");
    338 			break;
    339 		}
    340 		c->req = r;
    341 		if(c->nreply)
    342 			(*c->kickreply)(c);
    343 		else
    344 			rpcexec(c);
    345 		break;
    346 	case Qconfirm:
    347 		confirmread(r);
    348 		break;
    349 	case Qlog:
    350 		logread(r);
    351 		break;
    352 	case Qctl:
    353 		r->fid->aux = (void*)(uintptr)readlist((uintptr)r->fid->aux, keylist, r);
    354 		respond(r, nil);
    355 		break;
    356 	case Qneedkey:
    357 		needkeyread(r);
    358 		break;
    359 	case Qprotolist:
    360 		r->fid->aux = (void*)(uintptr)readlist((uintptr)r->fid->aux, protolist, r);
    361 		respond(r, nil);
    362 		break;
    363 	case Qconv:
    364 		r->fid->aux = (void*)(uintptr)readlist((uintptr)r->fid->aux, convlist, r);
    365 		respond(r, nil);
    366 		break;
    367 	}
    368 }
    369 
    370 static void
    371 fswrite(Req *r)
    372 {
    373 	int ret;
    374 	char err[ERRMAX], *s;
    375 	int (*strfn)(char*);
    376 	char *name;
    377 
    378 	switch((int)r->fid->qid.path){
    379 	default:
    380 		respond(r, "fswrite: cannot happen");
    381 		break;
    382 	case Qrpc:
    383 		if(rpcwrite(r->fid->aux, r->ifcall.data, r->ifcall.count) < 0){
    384 			rerrstr(err, sizeof err);
    385 			respond(r, err);
    386 		}else{
    387 			r->ofcall.count = r->ifcall.count;
    388 			respond(r, nil);
    389 		}
    390 		break;
    391 	case Qneedkey:
    392 		name = "needkey";
    393 		strfn = needkeywrite;
    394 		goto string;
    395 	case Qctl:
    396 		name = "ctl";
    397 		strfn = ctlwrite;
    398 		goto string;
    399 	case Qconfirm:
    400 		name = "confirm";
    401 		strfn = confirmwrite;
    402 	string:
    403 		s = emalloc(r->ifcall.count+1);
    404 		memmove(s, r->ifcall.data, r->ifcall.count);
    405 		s[r->ifcall.count] = '\0';
    406 		ret = (*strfn)(s);
    407 		free(s);
    408 		if(ret < 0){
    409 			rerrstr(err, sizeof err);
    410 			respond(r, err);
    411 			flog("write %s: %s", name, err);
    412 		}else{
    413 			r->ofcall.count = r->ifcall.count;
    414 			respond(r, nil);
    415 		}
    416 		break;
    417 	}
    418 }
    419 
    420 static void
    421 fsflush(Req *r)
    422 {
    423 	confirmflush(r->oldreq);
    424 	logflush(r->oldreq);
    425 	respond(r, nil);
    426 }
    427 
    428 static void
    429 fsdestroyfid(Fid *fid)
    430 {
    431 	if(fid->qid.path == Qrpc && fid->aux){
    432 		convhangup(fid->aux);
    433 		convclose(fid->aux);
    434 	}
    435 }
    436 
    437 static Channel *creq;
    438 static Channel *cfid, *cfidr;
    439 
    440 static void
    441 fsreqthread(void *v)
    442 {
    443 	Req *r;
    444 
    445 	USED(v);
    446 
    447 	while((r = recvp(creq)) != nil){
    448 		switch(r->ifcall.type){
    449 		default:
    450 			respond(r, "bug in fsreqthread");
    451 			break;
    452 		case Topen:
    453 			fsopen(r);
    454 			break;
    455 		case Tread:
    456 			fsread(r);
    457 			break;
    458 		case Twrite:
    459 			fswrite(r);
    460 			break;
    461 		case Tflush:
    462 			fsflush(r);
    463 			break;
    464 		}
    465 	}
    466 }
    467 
    468 static void
    469 fsclunkthread(void *v)
    470 {
    471 	Fid *f;
    472 
    473 	USED(v);
    474 
    475 	while((f = recvp(cfid)) != nil){
    476 		fsdestroyfid(f);
    477 		sendp(cfidr, 0);
    478 	}
    479 }
    480 
    481 static void
    482 fsproc(void *v)
    483 {
    484 	USED(v);
    485 
    486 	threadcreate(fsreqthread, nil, STACK);
    487 	threadcreate(fsclunkthread, nil, STACK);
    488 	threadexits(nil);
    489 }
    490 
    491 static void
    492 fsattach(Req *r)
    493 {
    494 	r->fid->qid = mkqid(QTDIR, qtop);
    495 	r->ofcall.qid = r->fid->qid;
    496 	respond(r, nil);
    497 }
    498 
    499 static void
    500 fssend(Req *r)
    501 {
    502 	sendp(creq, r);
    503 }
    504 
    505 static void
    506 fssendclunk(Fid *f)
    507 {
    508 	sendp(cfid, f);
    509 	recvp(cfidr);
    510 }
    511 
    512 void
    513 fsstart(Srv *s)
    514 {
    515 	USED(s);
    516 
    517 	if(extrafactotumdir)
    518 		qtop = Qroot;
    519 	else
    520 		qtop = Qfactotum;
    521 	creq = chancreate(sizeof(Req*), 0);
    522 	cfid = chancreate(sizeof(Fid*), 0);
    523 	cfidr = chancreate(sizeof(Fid*), 0);
    524 	proccreate(fsproc, nil, STACK);
    525 }
    526 
    527 Srv fs;
    528 
    529 void
    530 fsinit0(void)
    531 {
    532 	fs.attach = fsattach;
    533 	fs.walk1 = fswalk1;
    534 	fs.open = fssend;
    535 	fs.read = fssend;
    536 	fs.write = fssend;
    537 	fs.stat = fsstat;
    538 	fs.flush = fssend;
    539 	fs.destroyfid = fssendclunk;
    540 	fs.start = fsstart;
    541 }