xref: /plan9/sys/src/cmd/ramfs.c (revision ab3dc52f122c98aa4bc2bd64bd2292bb7b80fba2)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <auth.h>
43e12c5d1SDavid du Colombier #include <fcall.h>
53e12c5d1SDavid du Colombier 
63e12c5d1SDavid du Colombier /*
73e12c5d1SDavid du Colombier  * Rather than reading /adm/users, which is a lot of work for
83e12c5d1SDavid du Colombier  * a toy program, we assume all groups have the form
93e12c5d1SDavid du Colombier  *	NNN:user:user:
103e12c5d1SDavid du Colombier  * meaning that each user is the leader of his own group.
113e12c5d1SDavid du Colombier  */
123e12c5d1SDavid du Colombier 
133e12c5d1SDavid du Colombier enum
143e12c5d1SDavid du Colombier {
153e12c5d1SDavid du Colombier 	OPERM	= 0x3,		/* mask of all permission types in open mode */
166b6b9ac8SDavid du Colombier 	Nram	= 2048,
1746228ac7SDavid du Colombier 	Maxsize	= 768*1024*1024,
189a747e4fSDavid du Colombier 	Maxfdata	= 8192,
193e12c5d1SDavid du Colombier };
203e12c5d1SDavid du Colombier 
213e12c5d1SDavid du Colombier typedef struct Fid Fid;
223e12c5d1SDavid du Colombier typedef struct Ram Ram;
233e12c5d1SDavid du Colombier 
243e12c5d1SDavid du Colombier struct Fid
253e12c5d1SDavid du Colombier {
263e12c5d1SDavid du Colombier 	short	busy;
273e12c5d1SDavid du Colombier 	short	open;
283e12c5d1SDavid du Colombier 	short	rclose;
293e12c5d1SDavid du Colombier 	int	fid;
303e12c5d1SDavid du Colombier 	Fid	*next;
313e12c5d1SDavid du Colombier 	char	*user;
323e12c5d1SDavid du Colombier 	Ram	*ram;
333e12c5d1SDavid du Colombier };
343e12c5d1SDavid du Colombier 
353e12c5d1SDavid du Colombier struct Ram
363e12c5d1SDavid du Colombier {
373e12c5d1SDavid du Colombier 	short	busy;
383e12c5d1SDavid du Colombier 	short	open;
393e12c5d1SDavid du Colombier 	long	parent;		/* index in Ram array */
403e12c5d1SDavid du Colombier 	Qid	qid;
413e12c5d1SDavid du Colombier 	long	perm;
429a747e4fSDavid du Colombier 	char	*name;
433e12c5d1SDavid du Colombier 	ulong	atime;
443e12c5d1SDavid du Colombier 	ulong	mtime;
453e12c5d1SDavid du Colombier 	char	*user;
463e12c5d1SDavid du Colombier 	char	*group;
479a747e4fSDavid du Colombier 	char	*muid;
483e12c5d1SDavid du Colombier 	char	*data;
493e12c5d1SDavid du Colombier 	long	ndata;
503e12c5d1SDavid du Colombier };
513e12c5d1SDavid du Colombier 
523e12c5d1SDavid du Colombier enum
533e12c5d1SDavid du Colombier {
543e12c5d1SDavid du Colombier 	Pexec =		1,
553e12c5d1SDavid du Colombier 	Pwrite = 	2,
563e12c5d1SDavid du Colombier 	Pread = 	4,
573e12c5d1SDavid du Colombier 	Pother = 	1,
583e12c5d1SDavid du Colombier 	Pgroup = 	8,
593e12c5d1SDavid du Colombier 	Powner =	64,
603e12c5d1SDavid du Colombier };
613e12c5d1SDavid du Colombier 
623e12c5d1SDavid du Colombier ulong	path;		/* incremented for each new file */
633e12c5d1SDavid du Colombier Fid	*fids;
643e12c5d1SDavid du Colombier Ram	ram[Nram];
653e12c5d1SDavid du Colombier int	nram;
663e12c5d1SDavid du Colombier int	mfd[2];
679a747e4fSDavid du Colombier char	*user;
689a747e4fSDavid du Colombier uchar	mdata[IOHDRSZ+Maxfdata];
699a747e4fSDavid du Colombier uchar	rdata[Maxfdata];	/* buffer for data in reply */
709a747e4fSDavid du Colombier uchar statbuf[STATMAX];
713e12c5d1SDavid du Colombier Fcall thdr;
729a747e4fSDavid du Colombier Fcall	rhdr;
739a747e4fSDavid du Colombier int	messagesize = sizeof mdata;
743e12c5d1SDavid du Colombier 
753e12c5d1SDavid du Colombier Fid *	newfid(int);
769a747e4fSDavid du Colombier uint	ramstat(Ram*, uchar*, uint);
773e12c5d1SDavid du Colombier void	error(char*);
783e12c5d1SDavid du Colombier void	io(void);
793e12c5d1SDavid du Colombier void	*erealloc(void*, ulong);
803e12c5d1SDavid du Colombier void	*emalloc(ulong);
819a747e4fSDavid du Colombier char	*estrdup(char*);
823e12c5d1SDavid du Colombier void	usage(void);
833e12c5d1SDavid du Colombier int	perm(Fid*, Ram*, int);
843e12c5d1SDavid du Colombier 
859a747e4fSDavid du Colombier char	*rflush(Fid*), *rversion(Fid*), *rauth(Fid*),
869a747e4fSDavid du Colombier 	*rattach(Fid*), *rwalk(Fid*),
879a747e4fSDavid du Colombier 	*ropen(Fid*), *rcreate(Fid*),
883e12c5d1SDavid du Colombier 	*rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
89219b2ee8SDavid du Colombier 	*rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
903e12c5d1SDavid du Colombier 
919fa41221SDavid du Colombier int needfid[] = {
929fa41221SDavid du Colombier 	[Tversion] 0,
939fa41221SDavid du Colombier 	[Tflush] 0,
949fa41221SDavid du Colombier 	[Tauth] 0,
959fa41221SDavid du Colombier 	[Tattach] 0,
969fa41221SDavid du Colombier 	[Twalk] 1,
979fa41221SDavid du Colombier 	[Topen] 1,
989fa41221SDavid du Colombier 	[Tcreate] 1,
999fa41221SDavid du Colombier 	[Tread] 1,
1009fa41221SDavid du Colombier 	[Twrite] 1,
1019fa41221SDavid du Colombier 	[Tclunk] 1,
1029fa41221SDavid du Colombier 	[Tremove] 1,
1039fa41221SDavid du Colombier 	[Tstat] 1,
1049fa41221SDavid du Colombier 	[Twstat] 1,
1059fa41221SDavid du Colombier };
1069fa41221SDavid du Colombier 
1073e12c5d1SDavid du Colombier char 	*(*fcalls[])(Fid*) = {
1089a747e4fSDavid du Colombier 	[Tversion]	rversion,
1093e12c5d1SDavid du Colombier 	[Tflush]	rflush,
1109a747e4fSDavid du Colombier 	[Tauth]	rauth,
1113e12c5d1SDavid du Colombier 	[Tattach]	rattach,
1123e12c5d1SDavid du Colombier 	[Twalk]		rwalk,
1133e12c5d1SDavid du Colombier 	[Topen]		ropen,
1143e12c5d1SDavid du Colombier 	[Tcreate]	rcreate,
1153e12c5d1SDavid du Colombier 	[Tread]		rread,
1163e12c5d1SDavid du Colombier 	[Twrite]	rwrite,
1173e12c5d1SDavid du Colombier 	[Tclunk]	rclunk,
1183e12c5d1SDavid du Colombier 	[Tremove]	rremove,
1193e12c5d1SDavid du Colombier 	[Tstat]		rstat,
1203e12c5d1SDavid du Colombier 	[Twstat]	rwstat,
1213e12c5d1SDavid du Colombier };
1223e12c5d1SDavid du Colombier 
1233e12c5d1SDavid du Colombier char	Eperm[] =	"permission denied";
1243e12c5d1SDavid du Colombier char	Enotdir[] =	"not a directory";
1253ff48bf5SDavid du Colombier char	Enoauth[] =	"ramfs: authentication not required";
1263e12c5d1SDavid du Colombier char	Enotexist[] =	"file does not exist";
1273e12c5d1SDavid du Colombier char	Einuse[] =	"file in use";
1283e12c5d1SDavid du Colombier char	Eexist[] =	"file exists";
1299a747e4fSDavid du Colombier char	Eisdir[] =	"file is a directory";
1303e12c5d1SDavid du Colombier char	Enotowner[] =	"not owner";
1313e12c5d1SDavid du Colombier char	Eisopen[] = 	"file already open for I/O";
1323e12c5d1SDavid du Colombier char	Excl[] = 	"exclusive use file already open";
1333e12c5d1SDavid du Colombier char	Ename[] = 	"illegal name";
1349a747e4fSDavid du Colombier char	Eversion[] =	"unknown 9P version";
135162174bbSDavid du Colombier char	Enotempty[] =	"directory not empty";
1363e12c5d1SDavid du Colombier 
137219b2ee8SDavid du Colombier int debug;
1389a747e4fSDavid du Colombier int private;
139219b2ee8SDavid du Colombier 
1403e12c5d1SDavid du Colombier void
1413e12c5d1SDavid du Colombier notifyf(void *a, char *s)
1423e12c5d1SDavid du Colombier {
1433e12c5d1SDavid du Colombier 	USED(a);
1443e12c5d1SDavid du Colombier 	if(strncmp(s, "interrupt", 9) == 0)
1453e12c5d1SDavid du Colombier 		noted(NCONT);
1463e12c5d1SDavid du Colombier 	noted(NDFLT);
1473e12c5d1SDavid du Colombier }
1483e12c5d1SDavid du Colombier 
1493e12c5d1SDavid du Colombier void
1503e12c5d1SDavid du Colombier main(int argc, char *argv[])
1513e12c5d1SDavid du Colombier {
1523e12c5d1SDavid du Colombier 	Ram *r;
1533e12c5d1SDavid du Colombier 	char *defmnt;
1543e12c5d1SDavid du Colombier 	int p[2];
1553e12c5d1SDavid du Colombier 	int fd;
1563e12c5d1SDavid du Colombier 	int stdio = 0;
157b7b24591SDavid du Colombier 	char *service;
1583e12c5d1SDavid du Colombier 
159b7b24591SDavid du Colombier 	service = "ramfs";
1603e12c5d1SDavid du Colombier 	defmnt = "/tmp";
1613e12c5d1SDavid du Colombier 	ARGBEGIN{
1629a747e4fSDavid du Colombier 	case 'D':
163219b2ee8SDavid du Colombier 		debug = 1;
164219b2ee8SDavid du Colombier 		break;
1653e12c5d1SDavid du Colombier 	case 'i':
1663e12c5d1SDavid du Colombier 		defmnt = 0;
1673e12c5d1SDavid du Colombier 		stdio = 1;
1683e12c5d1SDavid du Colombier 		mfd[0] = 0;
1693e12c5d1SDavid du Colombier 		mfd[1] = 1;
1703e12c5d1SDavid du Colombier 		break;
1713e12c5d1SDavid du Colombier 	case 's':
1723e12c5d1SDavid du Colombier 		defmnt = 0;
1733e12c5d1SDavid du Colombier 		break;
1743e12c5d1SDavid du Colombier 	case 'm':
175*ab3dc52fSDavid du Colombier 		defmnt = EARGF(usage());
1763e12c5d1SDavid du Colombier 		break;
1779a747e4fSDavid du Colombier 	case 'p':
1789a747e4fSDavid du Colombier 		private++;
1799a747e4fSDavid du Colombier 		break;
180b7b24591SDavid du Colombier 	case 'S':
181b7b24591SDavid du Colombier 		defmnt = 0;
182b7b24591SDavid du Colombier 		service = EARGF(usage());
183b7b24591SDavid du Colombier 		break;
1843e12c5d1SDavid du Colombier 	default:
1853e12c5d1SDavid du Colombier 		usage();
1863e12c5d1SDavid du Colombier 	}ARGEND
1873e12c5d1SDavid du Colombier 
1883e12c5d1SDavid du Colombier 	if(pipe(p) < 0)
1893e12c5d1SDavid du Colombier 		error("pipe failed");
1903e12c5d1SDavid du Colombier 	if(!stdio){
1913e12c5d1SDavid du Colombier 		mfd[0] = p[0];
1923e12c5d1SDavid du Colombier 		mfd[1] = p[0];
1933e12c5d1SDavid du Colombier 		if(defmnt == 0){
194b7b24591SDavid du Colombier 			char buf[64];
195b7b24591SDavid du Colombier 			snprint(buf, sizeof buf, "#s/%s", service);
1969fa41221SDavid du Colombier 			fd = create(buf, OWRITE|ORCLOSE, 0666);
1973e12c5d1SDavid du Colombier 			if(fd < 0)
198b7b24591SDavid du Colombier 				error("create failed");
1993e12c5d1SDavid du Colombier 			sprint(buf, "%d", p[1]);
2003e12c5d1SDavid du Colombier 			if(write(fd, buf, strlen(buf)) < 0)
201b7b24591SDavid du Colombier 				error("writing service file");
2023e12c5d1SDavid du Colombier 		}
2033e12c5d1SDavid du Colombier 	}
2043e12c5d1SDavid du Colombier 
2059a747e4fSDavid du Colombier 	user = getuser();
2063e12c5d1SDavid du Colombier 	notify(notifyf);
2073e12c5d1SDavid du Colombier 	nram = 1;
2083e12c5d1SDavid du Colombier 	r = &ram[0];
2093e12c5d1SDavid du Colombier 	r->busy = 1;
2103e12c5d1SDavid du Colombier 	r->data = 0;
2113e12c5d1SDavid du Colombier 	r->ndata = 0;
2129a747e4fSDavid du Colombier 	r->perm = DMDIR | 0775;
2139a747e4fSDavid du Colombier 	r->qid.type = QTDIR;
2149a747e4fSDavid du Colombier 	r->qid.path = 0LL;
2153e12c5d1SDavid du Colombier 	r->qid.vers = 0;
2163e12c5d1SDavid du Colombier 	r->parent = 0;
2173e12c5d1SDavid du Colombier 	r->user = user;
2183e12c5d1SDavid du Colombier 	r->group = user;
2199a747e4fSDavid du Colombier 	r->muid = user;
2203e12c5d1SDavid du Colombier 	r->atime = time(0);
2213e12c5d1SDavid du Colombier 	r->mtime = r->atime;
2229a747e4fSDavid du Colombier 	r->name = estrdup(".");
2233e12c5d1SDavid du Colombier 
224219b2ee8SDavid du Colombier 	if(debug)
2259a747e4fSDavid du Colombier 		fmtinstall('F', fcallfmt);
2263e12c5d1SDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
2273e12c5d1SDavid du Colombier 	case -1:
2283e12c5d1SDavid du Colombier 		error("fork");
2293e12c5d1SDavid du Colombier 	case 0:
2303e12c5d1SDavid du Colombier 		close(p[1]);
2313e12c5d1SDavid du Colombier 		io();
2323e12c5d1SDavid du Colombier 		break;
2333e12c5d1SDavid du Colombier 	default:
2343e12c5d1SDavid du Colombier 		close(p[0]);	/* don't deadlock if child fails */
2359a747e4fSDavid du Colombier 		if(defmnt && mount(p[1], -1, defmnt, MREPL|MCREATE, "") < 0)
2363e12c5d1SDavid du Colombier 			error("mount failed");
2373e12c5d1SDavid du Colombier 	}
2383e12c5d1SDavid du Colombier 	exits(0);
2393e12c5d1SDavid du Colombier }
2403e12c5d1SDavid du Colombier 
2413e12c5d1SDavid du Colombier char*
2429a747e4fSDavid du Colombier rversion(Fid*)
2433e12c5d1SDavid du Colombier {
2443e12c5d1SDavid du Colombier 	Fid *f;
2453e12c5d1SDavid du Colombier 
2463e12c5d1SDavid du Colombier 	for(f = fids; f; f = f->next)
2473e12c5d1SDavid du Colombier 		if(f->busy)
2483e12c5d1SDavid du Colombier 			rclunk(f);
2499a747e4fSDavid du Colombier 	if(thdr.msize > sizeof mdata)
2509a747e4fSDavid du Colombier 		rhdr.msize = sizeof mdata;
2519a747e4fSDavid du Colombier 	else
2529a747e4fSDavid du Colombier 		rhdr.msize = thdr.msize;
2539a747e4fSDavid du Colombier 	messagesize = rhdr.msize;
2549a747e4fSDavid du Colombier 	if(strncmp(thdr.version, "9P2000", 6) != 0)
2559a747e4fSDavid du Colombier 		return Eversion;
2569a747e4fSDavid du Colombier 	rhdr.version = "9P2000";
2573e12c5d1SDavid du Colombier 	return 0;
2583e12c5d1SDavid du Colombier }
2593e12c5d1SDavid du Colombier 
2603e12c5d1SDavid du Colombier char*
2619a747e4fSDavid du Colombier rauth(Fid*)
2629a747e4fSDavid du Colombier {
2639a747e4fSDavid du Colombier 	return "ramfs: no authentication required";
2649a747e4fSDavid du Colombier }
2659a747e4fSDavid du Colombier 
2669a747e4fSDavid du Colombier char*
2673e12c5d1SDavid du Colombier rflush(Fid *f)
2683e12c5d1SDavid du Colombier {
2693e12c5d1SDavid du Colombier 	USED(f);
2703e12c5d1SDavid du Colombier 	return 0;
2713e12c5d1SDavid du Colombier }
2723e12c5d1SDavid du Colombier 
2733e12c5d1SDavid du Colombier char*
2743e12c5d1SDavid du Colombier rattach(Fid *f)
2753e12c5d1SDavid du Colombier {
2763e12c5d1SDavid du Colombier 	/* no authentication! */
2773e12c5d1SDavid du Colombier 	f->busy = 1;
2783e12c5d1SDavid du Colombier 	f->rclose = 0;
2793e12c5d1SDavid du Colombier 	f->ram = &ram[0];
2809a747e4fSDavid du Colombier 	rhdr.qid = f->ram->qid;
2819a747e4fSDavid du Colombier 	if(thdr.uname[0])
2829a747e4fSDavid du Colombier 		f->user = estrdup(thdr.uname);
2833e12c5d1SDavid du Colombier 	else
2843e12c5d1SDavid du Colombier 		f->user = "none";
2857dd7cddfSDavid du Colombier 	if(strcmp(user, "none") == 0)
2869a747e4fSDavid du Colombier 		user = f->user;
2873e12c5d1SDavid du Colombier 	return 0;
2883e12c5d1SDavid du Colombier }
2893e12c5d1SDavid du Colombier 
2903e12c5d1SDavid du Colombier char*
2919a747e4fSDavid du Colombier clone(Fid *f, Fid **nf)
2923e12c5d1SDavid du Colombier {
2933e12c5d1SDavid du Colombier 	if(f->open)
2943e12c5d1SDavid du Colombier 		return Eisopen;
2953e12c5d1SDavid du Colombier 	if(f->ram->busy == 0)
2963e12c5d1SDavid du Colombier 		return Enotexist;
2979a747e4fSDavid du Colombier 	*nf = newfid(thdr.newfid);
2989a747e4fSDavid du Colombier 	(*nf)->busy = 1;
2999a747e4fSDavid du Colombier 	(*nf)->open = 0;
3009a747e4fSDavid du Colombier 	(*nf)->rclose = 0;
3019a747e4fSDavid du Colombier 	(*nf)->ram = f->ram;
3029a747e4fSDavid du Colombier 	(*nf)->user = f->user;	/* no ref count; the leakage is minor */
3033e12c5d1SDavid du Colombier 	return 0;
3043e12c5d1SDavid du Colombier }
3053e12c5d1SDavid du Colombier 
3063e12c5d1SDavid du Colombier char*
3073e12c5d1SDavid du Colombier rwalk(Fid *f)
3083e12c5d1SDavid du Colombier {
3099a747e4fSDavid du Colombier 	Ram *r, *fram;
3103e12c5d1SDavid du Colombier 	char *name;
3113e12c5d1SDavid du Colombier 	Ram *parent;
3123e12c5d1SDavid du Colombier 	Fid *nf;
3133e12c5d1SDavid du Colombier 	char *err;
3149a747e4fSDavid du Colombier 	ulong t;
3159a747e4fSDavid du Colombier 	int i;
3163e12c5d1SDavid du Colombier 
3179a747e4fSDavid du Colombier 	err = nil;
3189a747e4fSDavid du Colombier 	nf = nil;
3199a747e4fSDavid du Colombier 	rhdr.nwqid = 0;
32059c21d95SDavid du Colombier 	if(thdr.newfid != thdr.fid){
3219a747e4fSDavid du Colombier 		err = clone(f, &nf);
3229a747e4fSDavid du Colombier 		if(err)
3239a747e4fSDavid du Colombier 			return err;
3249a747e4fSDavid du Colombier 		f = nf;	/* walk the new fid */
3259a747e4fSDavid du Colombier 	}
3269a747e4fSDavid du Colombier 	fram = f->ram;
3279a747e4fSDavid du Colombier 	if(thdr.nwname > 0){
3289a747e4fSDavid du Colombier 		t = time(0);
3299a747e4fSDavid du Colombier 		for(i=0; i<thdr.nwname && i<MAXWELEM; i++){
3309a747e4fSDavid du Colombier 			if((fram->qid.type & QTDIR) == 0){
3319a747e4fSDavid du Colombier 				err = Enotdir;
3329a747e4fSDavid du Colombier  				break;
3339a747e4fSDavid du Colombier 			}
3349a747e4fSDavid du Colombier 			if(fram->busy == 0){
3359a747e4fSDavid du Colombier 				err = Enotexist;
3369a747e4fSDavid du Colombier 				break;
3379a747e4fSDavid du Colombier 			}
3389a747e4fSDavid du Colombier 			fram->atime = t;
3399a747e4fSDavid du Colombier 			name = thdr.wname[i];
3409a747e4fSDavid du Colombier 			if(strcmp(name, ".") == 0){
3419a747e4fSDavid du Colombier     Found:
3429a747e4fSDavid du Colombier 				rhdr.nwqid++;
3439a747e4fSDavid du Colombier 				rhdr.wqid[i] = fram->qid;
3449a747e4fSDavid du Colombier 				continue;
3459a747e4fSDavid du Colombier 			}
3469a747e4fSDavid du Colombier 			parent = &ram[fram->parent];
3479a747e4fSDavid du Colombier 			if(!perm(f, parent, Pexec)){
3489a747e4fSDavid du Colombier 				err = Eperm;
3499a747e4fSDavid du Colombier 				break;
3509a747e4fSDavid du Colombier 			}
3519a747e4fSDavid du Colombier 			if(strcmp(name, "..") == 0){
3529a747e4fSDavid du Colombier 				fram = parent;
3539a747e4fSDavid du Colombier 				goto Found;
3549a747e4fSDavid du Colombier 			}
3559a747e4fSDavid du Colombier 			for(r=ram; r < &ram[nram]; r++)
3569a747e4fSDavid du Colombier 				if(r->busy && r->parent==fram-ram && strcmp(name, r->name)==0){
3579a747e4fSDavid du Colombier 					fram = r;
3589a747e4fSDavid du Colombier 					goto Found;
3599a747e4fSDavid du Colombier 				}
3609a747e4fSDavid du Colombier 			break;
3619a747e4fSDavid du Colombier 		}
3629a747e4fSDavid du Colombier 		if(i==0 && err == nil)
3639a747e4fSDavid du Colombier 			err = Enotexist;
3649a747e4fSDavid du Colombier 	}
3659a747e4fSDavid du Colombier 	if(nf != nil && (err!=nil || rhdr.nwqid<thdr.nwname)){
3669a747e4fSDavid du Colombier 		/* clunk the new fid, which is the one we walked */
3679a747e4fSDavid du Colombier 		f->busy = 0;
3689a747e4fSDavid du Colombier 		f->ram = nil;
3699a747e4fSDavid du Colombier 	}
3709fa41221SDavid du Colombier 	if(rhdr.nwqid > 0)
3719fa41221SDavid du Colombier 		err = nil;	/* didn't get everything in 9P2000 right! */
3729a747e4fSDavid du Colombier 	if(rhdr.nwqid == thdr.nwname)	/* update the fid after a successful walk */
3739a747e4fSDavid du Colombier 		f->ram = fram;
3743e12c5d1SDavid du Colombier 	return err;
3753e12c5d1SDavid du Colombier }
3763e12c5d1SDavid du Colombier 
3773e12c5d1SDavid du Colombier char *
3783e12c5d1SDavid du Colombier ropen(Fid *f)
3793e12c5d1SDavid du Colombier {
3803e12c5d1SDavid du Colombier 	Ram *r;
3813e12c5d1SDavid du Colombier 	int mode, trunc;
3823e12c5d1SDavid du Colombier 
3833e12c5d1SDavid du Colombier 	if(f->open)
3843e12c5d1SDavid du Colombier 		return Eisopen;
3853e12c5d1SDavid du Colombier 	r = f->ram;
3863e12c5d1SDavid du Colombier 	if(r->busy == 0)
3873e12c5d1SDavid du Colombier 		return Enotexist;
3889a747e4fSDavid du Colombier 	if(r->perm & DMEXCL)
3893e12c5d1SDavid du Colombier 		if(r->open)
3903e12c5d1SDavid du Colombier 			return Excl;
3919a747e4fSDavid du Colombier 	mode = thdr.mode;
3929a747e4fSDavid du Colombier 	if(r->qid.type & QTDIR){
3933e12c5d1SDavid du Colombier 		if(mode != OREAD)
3943e12c5d1SDavid du Colombier 			return Eperm;
3959a747e4fSDavid du Colombier 		rhdr.qid = r->qid;
3963e12c5d1SDavid du Colombier 		return 0;
3973e12c5d1SDavid du Colombier 	}
3983e12c5d1SDavid du Colombier 	if(mode & ORCLOSE){
3999a747e4fSDavid du Colombier 		/* can't remove root; must be able to write parent */
4009a747e4fSDavid du Colombier 		if(r->qid.path==0 || !perm(f, &ram[r->parent], Pwrite))
4013e12c5d1SDavid du Colombier 			return Eperm;
4023e12c5d1SDavid du Colombier 		f->rclose = 1;
4033e12c5d1SDavid du Colombier 	}
4043e12c5d1SDavid du Colombier 	trunc = mode & OTRUNC;
4053e12c5d1SDavid du Colombier 	mode &= OPERM;
4063e12c5d1SDavid du Colombier 	if(mode==OWRITE || mode==ORDWR || trunc)
4073e12c5d1SDavid du Colombier 		if(!perm(f, r, Pwrite))
4083e12c5d1SDavid du Colombier 			return Eperm;
4093e12c5d1SDavid du Colombier 	if(mode==OREAD || mode==ORDWR)
4103e12c5d1SDavid du Colombier 		if(!perm(f, r, Pread))
4113e12c5d1SDavid du Colombier 			return Eperm;
4123e12c5d1SDavid du Colombier 	if(mode==OEXEC)
4133e12c5d1SDavid du Colombier 		if(!perm(f, r, Pexec))
4143e12c5d1SDavid du Colombier 			return Eperm;
4159a747e4fSDavid du Colombier 	if(trunc && (r->perm&DMAPPEND)==0){
4163e12c5d1SDavid du Colombier 		r->ndata = 0;
4173e12c5d1SDavid du Colombier 		if(r->data)
4183e12c5d1SDavid du Colombier 			free(r->data);
4193e12c5d1SDavid du Colombier 		r->data = 0;
4203e12c5d1SDavid du Colombier 		r->qid.vers++;
4213e12c5d1SDavid du Colombier 	}
4229a747e4fSDavid du Colombier 	rhdr.qid = r->qid;
4239a747e4fSDavid du Colombier 	rhdr.iounit = messagesize-IOHDRSZ;
4243e12c5d1SDavid du Colombier 	f->open = 1;
4253e12c5d1SDavid du Colombier 	r->open++;
4263e12c5d1SDavid du Colombier 	return 0;
4273e12c5d1SDavid du Colombier }
4283e12c5d1SDavid du Colombier 
4293e12c5d1SDavid du Colombier char *
4303e12c5d1SDavid du Colombier rcreate(Fid *f)
4313e12c5d1SDavid du Colombier {
4323e12c5d1SDavid du Colombier 	Ram *r;
4333e12c5d1SDavid du Colombier 	char *name;
4343e12c5d1SDavid du Colombier 	long parent, prm;
4353e12c5d1SDavid du Colombier 
4363e12c5d1SDavid du Colombier 	if(f->open)
4373e12c5d1SDavid du Colombier 		return Eisopen;
4383e12c5d1SDavid du Colombier 	if(f->ram->busy == 0)
4393e12c5d1SDavid du Colombier 		return Enotexist;
4403e12c5d1SDavid du Colombier 	parent = f->ram - ram;
4419a747e4fSDavid du Colombier 	if((f->ram->qid.type&QTDIR) == 0)
4423e12c5d1SDavid du Colombier 		return Enotdir;
4433e12c5d1SDavid du Colombier 	/* must be able to write parent */
4443e12c5d1SDavid du Colombier 	if(!perm(f, f->ram, Pwrite))
4453e12c5d1SDavid du Colombier 		return Eperm;
4469a747e4fSDavid du Colombier 	prm = thdr.perm;
4479a747e4fSDavid du Colombier 	name = thdr.name;
4483e12c5d1SDavid du Colombier 	if(strcmp(name, ".")==0 || strcmp(name, "..")==0)
4493e12c5d1SDavid du Colombier 		return Ename;
4503e12c5d1SDavid du Colombier 	for(r=ram; r<&ram[nram]; r++)
4513e12c5d1SDavid du Colombier 		if(r->busy && parent==r->parent)
4523e12c5d1SDavid du Colombier 		if(strcmp((char*)name, r->name)==0)
4533e12c5d1SDavid du Colombier 			return Einuse;
4543e12c5d1SDavid du Colombier 	for(r=ram; r->busy; r++)
4553e12c5d1SDavid du Colombier 		if(r == &ram[Nram-1])
4563e12c5d1SDavid du Colombier 			return "no free ram resources";
4573e12c5d1SDavid du Colombier 	r->busy = 1;
4583e12c5d1SDavid du Colombier 	r->qid.path = ++path;
4593e12c5d1SDavid du Colombier 	r->qid.vers = 0;
4609a747e4fSDavid du Colombier 	if(prm & DMDIR)
4619a747e4fSDavid du Colombier 		r->qid.type |= QTDIR;
4623e12c5d1SDavid du Colombier 	r->parent = parent;
4639a747e4fSDavid du Colombier 	free(r->name);
4649a747e4fSDavid du Colombier 	r->name = estrdup(name);
4653e12c5d1SDavid du Colombier 	r->user = f->user;
4663e12c5d1SDavid du Colombier 	r->group = f->ram->group;
4679a747e4fSDavid du Colombier 	r->muid = f->ram->muid;
4689a747e4fSDavid du Colombier 	if(prm & DMDIR)
4693e12c5d1SDavid du Colombier 		prm = (prm&~0777) | (f->ram->perm&prm&0777);
4703e12c5d1SDavid du Colombier 	else
4713e12c5d1SDavid du Colombier 		prm = (prm&(~0777|0111)) | (f->ram->perm&prm&0666);
4723e12c5d1SDavid du Colombier 	r->perm = prm;
4733e12c5d1SDavid du Colombier 	r->ndata = 0;
4743e12c5d1SDavid du Colombier 	if(r-ram >= nram)
4753e12c5d1SDavid du Colombier 		nram = r - ram + 1;
4763e12c5d1SDavid du Colombier 	r->atime = time(0);
4773e12c5d1SDavid du Colombier 	r->mtime = r->atime;
4783e12c5d1SDavid du Colombier 	f->ram->mtime = r->atime;
4793e12c5d1SDavid du Colombier 	f->ram = r;
4809a747e4fSDavid du Colombier 	rhdr.qid = r->qid;
4819a747e4fSDavid du Colombier 	rhdr.iounit = messagesize-IOHDRSZ;
4823e12c5d1SDavid du Colombier 	f->open = 1;
4839a747e4fSDavid du Colombier 	if(thdr.mode & ORCLOSE)
4847dd7cddfSDavid du Colombier 		f->rclose = 1;
4853e12c5d1SDavid du Colombier 	r->open++;
4863e12c5d1SDavid du Colombier 	return 0;
4873e12c5d1SDavid du Colombier }
4883e12c5d1SDavid du Colombier 
4893e12c5d1SDavid du Colombier char*
4903e12c5d1SDavid du Colombier rread(Fid *f)
4913e12c5d1SDavid du Colombier {
4923e12c5d1SDavid du Colombier 	Ram *r;
4939a747e4fSDavid du Colombier 	uchar *buf;
4943e12c5d1SDavid du Colombier 	long off;
4959a747e4fSDavid du Colombier 	int n, m, cnt;
4963e12c5d1SDavid du Colombier 
4973e12c5d1SDavid du Colombier 	if(f->ram->busy == 0)
4983e12c5d1SDavid du Colombier 		return Enotexist;
4993e12c5d1SDavid du Colombier 	n = 0;
5009a747e4fSDavid du Colombier 	rhdr.count = 0;
5019a747e4fSDavid du Colombier 	off = thdr.offset;
5029a747e4fSDavid du Colombier 	buf = rdata;
5039a747e4fSDavid du Colombier 	cnt = thdr.count;
5049a747e4fSDavid du Colombier 	if(cnt > messagesize)	/* shouldn't happen, anyway */
5059a747e4fSDavid du Colombier 		cnt = messagesize;
5069a747e4fSDavid du Colombier 	if(f->ram->qid.type & QTDIR){
5079a747e4fSDavid du Colombier 		for(r=ram+1; off > 0; r++){
5083e12c5d1SDavid du Colombier 			if(r->busy && r->parent==f->ram-ram)
5099a747e4fSDavid du Colombier 				off -= ramstat(r, statbuf, sizeof statbuf);
5103e12c5d1SDavid du Colombier 			if(r == &ram[nram-1])
5113e12c5d1SDavid du Colombier 				return 0;
5123e12c5d1SDavid du Colombier 		}
5133e12c5d1SDavid du Colombier 		for(; r<&ram[nram] && n < cnt; r++){
5143e12c5d1SDavid du Colombier 			if(!r->busy || r->parent!=f->ram-ram)
5153e12c5d1SDavid du Colombier 				continue;
5169a747e4fSDavid du Colombier 			m = ramstat(r, buf+n, cnt-n);
5179a747e4fSDavid du Colombier 			if(m == 0)
5189a747e4fSDavid du Colombier 				break;
5199a747e4fSDavid du Colombier 			n += m;
5203e12c5d1SDavid du Colombier 		}
5219a747e4fSDavid du Colombier 		rhdr.data = (char*)rdata;
5229a747e4fSDavid du Colombier 		rhdr.count = n;
5233e12c5d1SDavid du Colombier 		return 0;
5243e12c5d1SDavid du Colombier 	}
5253e12c5d1SDavid du Colombier 	r = f->ram;
5263e12c5d1SDavid du Colombier 	if(off >= r->ndata)
5273e12c5d1SDavid du Colombier 		return 0;
5283e12c5d1SDavid du Colombier 	r->atime = time(0);
5293e12c5d1SDavid du Colombier 	n = cnt;
5303e12c5d1SDavid du Colombier 	if(off+n > r->ndata)
5313e12c5d1SDavid du Colombier 		n = r->ndata - off;
5329a747e4fSDavid du Colombier 	rhdr.data = r->data+off;
5339a747e4fSDavid du Colombier 	rhdr.count = n;
5343e12c5d1SDavid du Colombier 	return 0;
5353e12c5d1SDavid du Colombier }
5363e12c5d1SDavid du Colombier 
5373e12c5d1SDavid du Colombier char*
5383e12c5d1SDavid du Colombier rwrite(Fid *f)
5393e12c5d1SDavid du Colombier {
5403e12c5d1SDavid du Colombier 	Ram *r;
5413e12c5d1SDavid du Colombier 	ulong off;
5423e12c5d1SDavid du Colombier 	int cnt;
5433e12c5d1SDavid du Colombier 
5443e12c5d1SDavid du Colombier 	r = f->ram;
5453e12c5d1SDavid du Colombier 	if(r->busy == 0)
5463e12c5d1SDavid du Colombier 		return Enotexist;
5479a747e4fSDavid du Colombier 	off = thdr.offset;
5489a747e4fSDavid du Colombier 	if(r->perm & DMAPPEND)
5493e12c5d1SDavid du Colombier 		off = r->ndata;
5509a747e4fSDavid du Colombier 	cnt = thdr.count;
5519a747e4fSDavid du Colombier 	if(r->qid.type & QTDIR)
5529a747e4fSDavid du Colombier 		return Eisdir;
5537dd7cddfSDavid du Colombier 	if(off+cnt >= Maxsize)		/* sanity check */
5543e12c5d1SDavid du Colombier 		return "write too big";
5553e12c5d1SDavid du Colombier 	if(off+cnt > r->ndata)
5563e12c5d1SDavid du Colombier 		r->data = erealloc(r->data, off+cnt);
5573e12c5d1SDavid du Colombier 	if(off > r->ndata)
5583e12c5d1SDavid du Colombier 		memset(r->data+r->ndata, 0, off-r->ndata);
5593e12c5d1SDavid du Colombier 	if(off+cnt > r->ndata)
5603e12c5d1SDavid du Colombier 		r->ndata = off+cnt;
5619a747e4fSDavid du Colombier 	memmove(r->data+off, thdr.data, cnt);
5623e12c5d1SDavid du Colombier 	r->qid.vers++;
5633e12c5d1SDavid du Colombier 	r->mtime = time(0);
5649a747e4fSDavid du Colombier 	rhdr.count = cnt;
5653e12c5d1SDavid du Colombier 	return 0;
5663e12c5d1SDavid du Colombier }
5673e12c5d1SDavid du Colombier 
568162174bbSDavid du Colombier static int
569162174bbSDavid du Colombier emptydir(Ram *dr)
570162174bbSDavid du Colombier {
571162174bbSDavid du Colombier 	long didx = dr - ram;
572162174bbSDavid du Colombier 	Ram *r;
573162174bbSDavid du Colombier 
574162174bbSDavid du Colombier 	for(r=ram; r<&ram[nram]; r++)
575162174bbSDavid du Colombier 		if(r->busy && didx==r->parent)
576162174bbSDavid du Colombier 			return 0;
577162174bbSDavid du Colombier 	return 1;
578162174bbSDavid du Colombier }
579162174bbSDavid du Colombier 
580162174bbSDavid du Colombier char *
5813e12c5d1SDavid du Colombier realremove(Ram *r)
5823e12c5d1SDavid du Colombier {
583162174bbSDavid du Colombier 	if(r->qid.type & QTDIR && !emptydir(r))
584162174bbSDavid du Colombier 		return Enotempty;
5853e12c5d1SDavid du Colombier 	r->ndata = 0;
5863e12c5d1SDavid du Colombier 	if(r->data)
5873e12c5d1SDavid du Colombier 		free(r->data);
5883e12c5d1SDavid du Colombier 	r->data = 0;
5893e12c5d1SDavid du Colombier 	r->parent = 0;
5909a747e4fSDavid du Colombier 	memset(&r->qid, 0, sizeof r->qid);
5919a747e4fSDavid du Colombier 	free(r->name);
5929a747e4fSDavid du Colombier 	r->name = nil;
5933e12c5d1SDavid du Colombier 	r->busy = 0;
594162174bbSDavid du Colombier 	return nil;
5953e12c5d1SDavid du Colombier }
5963e12c5d1SDavid du Colombier 
5973e12c5d1SDavid du Colombier char *
5983e12c5d1SDavid du Colombier rclunk(Fid *f)
5993e12c5d1SDavid du Colombier {
600162174bbSDavid du Colombier 	char *e = nil;
601162174bbSDavid du Colombier 
6023e12c5d1SDavid du Colombier 	if(f->open)
6033e12c5d1SDavid du Colombier 		f->ram->open--;
6043e12c5d1SDavid du Colombier 	if(f->rclose)
605162174bbSDavid du Colombier 		e = realremove(f->ram);
6063e12c5d1SDavid du Colombier 	f->busy = 0;
6073e12c5d1SDavid du Colombier 	f->open = 0;
6083e12c5d1SDavid du Colombier 	f->ram = 0;
609162174bbSDavid du Colombier 	return e;
6103e12c5d1SDavid du Colombier }
6113e12c5d1SDavid du Colombier 
6123e12c5d1SDavid du Colombier char *
6133e12c5d1SDavid du Colombier rremove(Fid *f)
6143e12c5d1SDavid du Colombier {
6153e12c5d1SDavid du Colombier 	Ram *r;
6163e12c5d1SDavid du Colombier 
6173e12c5d1SDavid du Colombier 	if(f->open)
6183e12c5d1SDavid du Colombier 		f->ram->open--;
6193e12c5d1SDavid du Colombier 	f->busy = 0;
6203e12c5d1SDavid du Colombier 	f->open = 0;
6213e12c5d1SDavid du Colombier 	r = f->ram;
6223e12c5d1SDavid du Colombier 	f->ram = 0;
6239a747e4fSDavid du Colombier 	if(r->qid.path == 0 || !perm(f, &ram[r->parent], Pwrite))
6243e12c5d1SDavid du Colombier 		return Eperm;
6253e12c5d1SDavid du Colombier 	ram[r->parent].mtime = time(0);
626162174bbSDavid du Colombier 	return realremove(r);
6273e12c5d1SDavid du Colombier }
6283e12c5d1SDavid du Colombier 
6293e12c5d1SDavid du Colombier char *
6303e12c5d1SDavid du Colombier rstat(Fid *f)
6313e12c5d1SDavid du Colombier {
6323e12c5d1SDavid du Colombier 	if(f->ram->busy == 0)
6333e12c5d1SDavid du Colombier 		return Enotexist;
6349a747e4fSDavid du Colombier 	rhdr.nstat = ramstat(f->ram, statbuf, sizeof statbuf);
6359a747e4fSDavid du Colombier 	rhdr.stat = statbuf;
6363e12c5d1SDavid du Colombier 	return 0;
6373e12c5d1SDavid du Colombier }
6383e12c5d1SDavid du Colombier 
6393e12c5d1SDavid du Colombier char *
6403e12c5d1SDavid du Colombier rwstat(Fid *f)
6413e12c5d1SDavid du Colombier {
6423e12c5d1SDavid du Colombier 	Ram *r, *s;
6433e12c5d1SDavid du Colombier 	Dir dir;
6443e12c5d1SDavid du Colombier 
6453e12c5d1SDavid du Colombier 	if(f->ram->busy == 0)
6463e12c5d1SDavid du Colombier 		return Enotexist;
6479a747e4fSDavid du Colombier 	convM2D(thdr.stat, thdr.nstat, &dir, (char*)statbuf);
6483e12c5d1SDavid du Colombier 	r = f->ram;
6493e12c5d1SDavid du Colombier 
6503e12c5d1SDavid du Colombier 	/*
6519a747e4fSDavid du Colombier 	 * To change length, must have write permission on file.
6529a747e4fSDavid du Colombier 	 */
6539a747e4fSDavid du Colombier 	if(dir.length!=~0 && dir.length!=r->ndata){
6549a747e4fSDavid du Colombier 	 	if(!perm(f, r, Pwrite))
6559a747e4fSDavid du Colombier 			return Eperm;
6569a747e4fSDavid du Colombier 	}
6579a747e4fSDavid du Colombier 
6589a747e4fSDavid du Colombier 	/*
6593e12c5d1SDavid du Colombier 	 * To change name, must have write permission in parent
6603e12c5d1SDavid du Colombier 	 * and name must be unique.
6613e12c5d1SDavid du Colombier 	 */
6629a747e4fSDavid du Colombier 	if(dir.name[0]!='\0' && strcmp(dir.name, r->name)!=0){
6633e12c5d1SDavid du Colombier 	 	if(!perm(f, &ram[r->parent], Pwrite))
6643e12c5d1SDavid du Colombier 			return Eperm;
6653e12c5d1SDavid du Colombier 		for(s=ram; s<&ram[nram]; s++)
6663e12c5d1SDavid du Colombier 			if(s->busy && s->parent==r->parent)
6673e12c5d1SDavid du Colombier 			if(strcmp(dir.name, s->name)==0)
6683e12c5d1SDavid du Colombier 				return Eexist;
6693e12c5d1SDavid du Colombier 	}
6703e12c5d1SDavid du Colombier 
6713e12c5d1SDavid du Colombier 	/*
6729a747e4fSDavid du Colombier 	 * To change mode, must be owner or group leader.
6733e12c5d1SDavid du Colombier 	 * Because of lack of users file, leader=>group itself.
6743e12c5d1SDavid du Colombier 	 */
6759a747e4fSDavid du Colombier 	if(dir.mode!=~0 && r->perm!=dir.mode){
6763e12c5d1SDavid du Colombier 		if(strcmp(f->user, r->user) != 0)
6773e12c5d1SDavid du Colombier 		if(strcmp(f->user, r->group) != 0)
6783e12c5d1SDavid du Colombier 			return Enotowner;
6793e12c5d1SDavid du Colombier 	}
6803e12c5d1SDavid du Colombier 
6813e12c5d1SDavid du Colombier 	/*
6823e12c5d1SDavid du Colombier 	 * To change group, must be owner and member of new group,
6833e12c5d1SDavid du Colombier 	 * or leader of current group and leader of new group.
6843e12c5d1SDavid du Colombier 	 * Second case cannot happen, but we check anyway.
6853e12c5d1SDavid du Colombier 	 */
6869a747e4fSDavid du Colombier 	if(dir.gid[0]!='\0' && strcmp(r->group, dir.gid)!=0){
6873e12c5d1SDavid du Colombier 		if(strcmp(f->user, r->user) == 0)
688dc5a79c1SDavid du Colombier 	//	if(strcmp(f->user, dir.gid) == 0)
6893e12c5d1SDavid du Colombier 			goto ok;
6903e12c5d1SDavid du Colombier 		if(strcmp(f->user, r->group) == 0)
6913e12c5d1SDavid du Colombier 		if(strcmp(f->user, dir.gid) == 0)
6923e12c5d1SDavid du Colombier 			goto ok;
6933e12c5d1SDavid du Colombier 		return Enotowner;
6943e12c5d1SDavid du Colombier 		ok:;
6953e12c5d1SDavid du Colombier 	}
6963e12c5d1SDavid du Colombier 
6973e12c5d1SDavid du Colombier 	/* all ok; do it */
6989a747e4fSDavid du Colombier 	if(dir.mode != ~0){
6999a747e4fSDavid du Colombier 		dir.mode &= ~DMDIR;	/* cannot change dir bit */
7009a747e4fSDavid du Colombier 		dir.mode |= r->perm&DMDIR;
7013e12c5d1SDavid du Colombier 		r->perm = dir.mode;
7029a747e4fSDavid du Colombier 	}
7039a747e4fSDavid du Colombier 	if(dir.name[0] != '\0'){
7049a747e4fSDavid du Colombier 		free(r->name);
7059a747e4fSDavid du Colombier 		r->name = estrdup(dir.name);
7069a747e4fSDavid du Colombier 	}
7079a747e4fSDavid du Colombier 	if(dir.gid[0] != '\0')
7089a747e4fSDavid du Colombier 		r->group = estrdup(dir.gid);
7099a747e4fSDavid du Colombier 	if(dir.length!=~0 && dir.length!=r->ndata){
7109a747e4fSDavid du Colombier 		r->data = erealloc(r->data, dir.length);
7119a747e4fSDavid du Colombier 		if(r->ndata < dir.length)
7129a747e4fSDavid du Colombier 			memset(r->data+r->ndata, 0, dir.length-r->ndata);
7139a747e4fSDavid du Colombier 		r->ndata = dir.length;
7149a747e4fSDavid du Colombier 	}
7153e12c5d1SDavid du Colombier 	ram[r->parent].mtime = time(0);
7163e12c5d1SDavid du Colombier 	return 0;
7173e12c5d1SDavid du Colombier }
7183e12c5d1SDavid du Colombier 
7199a747e4fSDavid du Colombier uint
7209a747e4fSDavid du Colombier ramstat(Ram *r, uchar *buf, uint nbuf)
7213e12c5d1SDavid du Colombier {
7226b6b9ac8SDavid du Colombier 	int n;
7233e12c5d1SDavid du Colombier 	Dir dir;
7243e12c5d1SDavid du Colombier 
7259a747e4fSDavid du Colombier 	dir.name = r->name;
7263e12c5d1SDavid du Colombier 	dir.qid = r->qid;
7273e12c5d1SDavid du Colombier 	dir.mode = r->perm;
7283e12c5d1SDavid du Colombier 	dir.length = r->ndata;
7299a747e4fSDavid du Colombier 	dir.uid = r->user;
7309a747e4fSDavid du Colombier 	dir.gid = r->group;
7319a747e4fSDavid du Colombier 	dir.muid = r->muid;
7323e12c5d1SDavid du Colombier 	dir.atime = r->atime;
7333e12c5d1SDavid du Colombier 	dir.mtime = r->mtime;
7346b6b9ac8SDavid du Colombier 	n = convD2M(&dir, buf, nbuf);
7356b6b9ac8SDavid du Colombier 	if(n > 2)
7366b6b9ac8SDavid du Colombier 		return n;
7376b6b9ac8SDavid du Colombier 	return 0;
7383e12c5d1SDavid du Colombier }
7393e12c5d1SDavid du Colombier 
7403e12c5d1SDavid du Colombier Fid *
7413e12c5d1SDavid du Colombier newfid(int fid)
7423e12c5d1SDavid du Colombier {
7433e12c5d1SDavid du Colombier 	Fid *f, *ff;
7443e12c5d1SDavid du Colombier 
7453e12c5d1SDavid du Colombier 	ff = 0;
7463e12c5d1SDavid du Colombier 	for(f = fids; f; f = f->next)
7473e12c5d1SDavid du Colombier 		if(f->fid == fid)
7483e12c5d1SDavid du Colombier 			return f;
7493e12c5d1SDavid du Colombier 		else if(!ff && !f->busy)
7503e12c5d1SDavid du Colombier 			ff = f;
7513e12c5d1SDavid du Colombier 	if(ff){
7523e12c5d1SDavid du Colombier 		ff->fid = fid;
7533e12c5d1SDavid du Colombier 		return ff;
7543e12c5d1SDavid du Colombier 	}
7553e12c5d1SDavid du Colombier 	f = emalloc(sizeof *f);
7567dd7cddfSDavid du Colombier 	f->ram = nil;
7573e12c5d1SDavid du Colombier 	f->fid = fid;
7583e12c5d1SDavid du Colombier 	f->next = fids;
7593e12c5d1SDavid du Colombier 	fids = f;
7603e12c5d1SDavid du Colombier 	return f;
7613e12c5d1SDavid du Colombier }
7623e12c5d1SDavid du Colombier 
7633e12c5d1SDavid du Colombier void
7643e12c5d1SDavid du Colombier io(void)
7653e12c5d1SDavid du Colombier {
76624e2e655SDavid du Colombier 	char *err, buf[40];
7679a747e4fSDavid du Colombier 	int n, pid, ctl;
7689fa41221SDavid du Colombier 	Fid *fid;
7699a747e4fSDavid du Colombier 
7709a747e4fSDavid du Colombier 	pid = getpid();
7719a747e4fSDavid du Colombier 	if(private){
7729a747e4fSDavid du Colombier 		snprint(buf, sizeof buf, "/proc/%d/ctl", pid);
7739a747e4fSDavid du Colombier 		ctl = open(buf, OWRITE);
7749a747e4fSDavid du Colombier 		if(ctl < 0){
7759a747e4fSDavid du Colombier 			fprint(2, "can't protect ramfs\n");
7769a747e4fSDavid du Colombier 		}else{
7779a747e4fSDavid du Colombier 			fprint(ctl, "noswap\n");
7789a747e4fSDavid du Colombier 			fprint(ctl, "private\n");
7799a747e4fSDavid du Colombier 			close(ctl);
7809a747e4fSDavid du Colombier 		}
7819a747e4fSDavid du Colombier 	}
7823e12c5d1SDavid du Colombier 
7833e12c5d1SDavid du Colombier 	for(;;){
7843e12c5d1SDavid du Colombier 		/*
7853e12c5d1SDavid du Colombier 		 * reading from a pipe or a network device
7869a747e4fSDavid du Colombier 		 * will give an error after a few eof reads.
7873e12c5d1SDavid du Colombier 		 * however, we cannot tell the difference
7883e12c5d1SDavid du Colombier 		 * between a zero-length read and an interrupt
7893e12c5d1SDavid du Colombier 		 * on the processes writing to us,
7909a747e4fSDavid du Colombier 		 * so we wait for the error.
7913e12c5d1SDavid du Colombier 		 */
7929a747e4fSDavid du Colombier 		n = read9pmsg(mfd[0], mdata, messagesize);
79324e2e655SDavid du Colombier 		if(n < 0){
79424e2e655SDavid du Colombier 			errstr(buf, sizeof buf);
79524e2e655SDavid du Colombier 			if(buf[0]=='\0' || strstr(buf, "hungup"))
79624e2e655SDavid du Colombier 				exits("");
79724e2e655SDavid du Colombier 			error("mount read");
79824e2e655SDavid du Colombier 		}
7993e12c5d1SDavid du Colombier 		if(n < 0)
8003e12c5d1SDavid du Colombier 			error("mount read");
8019a747e4fSDavid du Colombier 		if(n == 0)
8029a747e4fSDavid du Colombier 			continue;
8039a747e4fSDavid du Colombier 		if(convM2S(mdata, n, &thdr) == 0)
8043e12c5d1SDavid du Colombier 			continue;
8053e12c5d1SDavid du Colombier 
806219b2ee8SDavid du Colombier 		if(debug)
8079a747e4fSDavid du Colombier 			fprint(2, "ramfs %d:<-%F\n", pid, &thdr);
8083e12c5d1SDavid du Colombier 
8099fa41221SDavid du Colombier 		if(thdr.type<0 || thdr.type>=nelem(fcalls) || !fcalls[thdr.type])
8103e12c5d1SDavid du Colombier 			err = "bad fcall type";
8119fa41221SDavid du Colombier 		else if(((fid=newfid(thdr.fid))==nil || !fid->ram) && needfid[thdr.type])
8129fa41221SDavid du Colombier 			err = "fid not in use";
8133e12c5d1SDavid du Colombier 		else
8149fa41221SDavid du Colombier 			err = (*fcalls[thdr.type])(fid);
8153e12c5d1SDavid du Colombier 		if(err){
8169a747e4fSDavid du Colombier 			rhdr.type = Rerror;
8179a747e4fSDavid du Colombier 			rhdr.ename = err;
8183e12c5d1SDavid du Colombier 		}else{
8199a747e4fSDavid du Colombier 			rhdr.type = thdr.type + 1;
8209a747e4fSDavid du Colombier 			rhdr.fid = thdr.fid;
8213e12c5d1SDavid du Colombier 		}
8229a747e4fSDavid du Colombier 		rhdr.tag = thdr.tag;
823219b2ee8SDavid du Colombier 		if(debug)
8249a747e4fSDavid du Colombier 			fprint(2, "ramfs %d:->%F\n", pid, &rhdr);/**/
8259a747e4fSDavid du Colombier 		n = convS2M(&rhdr, mdata, messagesize);
8269a747e4fSDavid du Colombier 		if(n == 0)
8279a747e4fSDavid du Colombier 			error("convS2M error on write");
8283e12c5d1SDavid du Colombier 		if(write(mfd[1], mdata, n) != n)
8293e12c5d1SDavid du Colombier 			error("mount write");
8303e12c5d1SDavid du Colombier 	}
8313e12c5d1SDavid du Colombier }
8323e12c5d1SDavid du Colombier 
8333e12c5d1SDavid du Colombier int
8343e12c5d1SDavid du Colombier perm(Fid *f, Ram *r, int p)
8353e12c5d1SDavid du Colombier {
8363e12c5d1SDavid du Colombier 	if((p*Pother) & r->perm)
8373e12c5d1SDavid du Colombier 		return 1;
8383e12c5d1SDavid du Colombier 	if(strcmp(f->user, r->group)==0 && ((p*Pgroup) & r->perm))
8393e12c5d1SDavid du Colombier 		return 1;
8403e12c5d1SDavid du Colombier 	if(strcmp(f->user, r->user)==0 && ((p*Powner) & r->perm))
8413e12c5d1SDavid du Colombier 		return 1;
8423e12c5d1SDavid du Colombier 	return 0;
8433e12c5d1SDavid du Colombier }
8443e12c5d1SDavid du Colombier 
8453e12c5d1SDavid du Colombier void
8463e12c5d1SDavid du Colombier error(char *s)
8473e12c5d1SDavid du Colombier {
848219b2ee8SDavid du Colombier 	fprint(2, "%s: %s: %r\n", argv0, s);
8493e12c5d1SDavid du Colombier 	exits(s);
8503e12c5d1SDavid du Colombier }
8513e12c5d1SDavid du Colombier 
8523e12c5d1SDavid du Colombier void *
8533e12c5d1SDavid du Colombier emalloc(ulong n)
8543e12c5d1SDavid du Colombier {
8553e12c5d1SDavid du Colombier 	void *p;
8563e12c5d1SDavid du Colombier 
8573e12c5d1SDavid du Colombier 	p = malloc(n);
8583e12c5d1SDavid du Colombier 	if(!p)
8593e12c5d1SDavid du Colombier 		error("out of memory");
8607dd7cddfSDavid du Colombier 	memset(p, 0, n);
8613e12c5d1SDavid du Colombier 	return p;
8623e12c5d1SDavid du Colombier }
8633e12c5d1SDavid du Colombier 
8643e12c5d1SDavid du Colombier void *
8653e12c5d1SDavid du Colombier erealloc(void *p, ulong n)
8663e12c5d1SDavid du Colombier {
8673e12c5d1SDavid du Colombier 	p = realloc(p, n);
8683e12c5d1SDavid du Colombier 	if(!p)
8693e12c5d1SDavid du Colombier 		error("out of memory");
8703e12c5d1SDavid du Colombier 	return p;
8713e12c5d1SDavid du Colombier }
8723e12c5d1SDavid du Colombier 
8739a747e4fSDavid du Colombier char *
8749a747e4fSDavid du Colombier estrdup(char *q)
8759a747e4fSDavid du Colombier {
8769a747e4fSDavid du Colombier 	char *p;
8779a747e4fSDavid du Colombier 	int n;
8789a747e4fSDavid du Colombier 
8799a747e4fSDavid du Colombier 	n = strlen(q)+1;
8809a747e4fSDavid du Colombier 	p = malloc(n);
8819a747e4fSDavid du Colombier 	if(!p)
8829a747e4fSDavid du Colombier 		error("out of memory");
8839a747e4fSDavid du Colombier 	memmove(p, q, n);
8849a747e4fSDavid du Colombier 	return p;
8859a747e4fSDavid du Colombier }
8869a747e4fSDavid du Colombier 
8873e12c5d1SDavid du Colombier void
8883e12c5d1SDavid du Colombier usage(void)
8893e12c5d1SDavid du Colombier {
890*ab3dc52fSDavid du Colombier 	fprint(2, "usage: %s [-Dips] [-m mountpoint] [-S srvname]\n", argv0);
8913e12c5d1SDavid du Colombier 	exits("usage");
8923e12c5d1SDavid du Colombier }
893