xref: /plan9-contrib/sys/src/cmd/ramfs.c (revision 2ec6491f4460014c01f3ea5c06b30b1a392b0bb2)
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 
6 /*
7  * Rather than reading /adm/users, which is a lot of work for
8  * a toy program, we assume all groups have the form
9  *	NNN:user:user:
10  * meaning that each user is the leader of his own group.
11  */
12 
13 enum
14 {
15 	OPERM	= 0x3,		/* mask of all permission types in open mode */
16 	Nram	= 1024,
17 	Maxsize	= 768*1024*1024,
18 	Maxfdata	= 16*1024,
19 	Maxulong= (1ULL << 32) - 1,
20 };
21 
22 typedef struct Fid Fid;
23 typedef struct Ram Ram;
24 
25 struct Fid
26 {
27 	short	busy;
28 	short	open;
29 	short	rclose;
30 	int	fid;
31 	Fid	*next;
32 	char	*user;
33 	Ram	*ram;
34 };
35 
36 struct Ram
37 {
38 	short	busy;
39 	short	open;
40 	long	parent;		/* index in Ram array */
41 	Qid	qid;
42 	long	perm;
43 	char	*name;
44 	ulong	atime;
45 	ulong	mtime;
46 	char	*user;
47 	char	*group;
48 	char	*muid;
49 	char	*data;
50 	long	ndata;
51 };
52 
53 enum
54 {
55 	Pexec =		1,
56 	Pwrite = 	2,
57 	Pread = 	4,
58 	Pother = 	1,
59 	Pgroup = 	8,
60 	Powner =	64,
61 };
62 
63 ulong	path;		/* incremented for each new file */
64 Fid	*fids;
65 Ram	*ram;
66 int	maxnram = Nram;
67 int	nram;
68 int	mfd[2];
69 char	*user;
70 uchar	mdata[IOHDRSZ+Maxfdata];
71 uchar	rdata[Maxfdata];	/* buffer for data in reply */
72 uchar statbuf[STATMAX];
73 Fcall thdr;
74 Fcall	rhdr;
75 int	messagesize = sizeof mdata;
76 
77 Fid *	newfid(int);
78 uint	ramstat(Ram*, uchar*, uint);
79 void	error(char*);
80 void	io(void);
81 void	*erealloc(void*, ulong);
82 void	*emalloc(ulong);
83 char	*estrdup(char*);
84 void	usage(void);
85 int	perm(Fid*, Ram*, int);
86 Ram	*ramexpand(Ram*);
87 
88 char	*rflush(Fid*), *rversion(Fid*), *rauth(Fid*),
89 	*rattach(Fid*), *rwalk(Fid*),
90 	*ropen(Fid*), *rcreate(Fid*),
91 	*rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
92 	*rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
93 
94 int needfid[] = {
95 	[Tversion] 0,
96 	[Tflush] 0,
97 	[Tauth] 0,
98 	[Tattach] 0,
99 	[Twalk] 1,
100 	[Topen] 1,
101 	[Tcreate] 1,
102 	[Tread] 1,
103 	[Twrite] 1,
104 	[Tclunk] 1,
105 	[Tremove] 1,
106 	[Tstat] 1,
107 	[Twstat] 1,
108 };
109 
110 char 	*(*fcalls[])(Fid*) = {
111 	[Tversion]	rversion,
112 	[Tflush]	rflush,
113 	[Tauth]	rauth,
114 	[Tattach]	rattach,
115 	[Twalk]		rwalk,
116 	[Topen]		ropen,
117 	[Tcreate]	rcreate,
118 	[Tread]		rread,
119 	[Twrite]	rwrite,
120 	[Tclunk]	rclunk,
121 	[Tremove]	rremove,
122 	[Tstat]		rstat,
123 	[Twstat]	rwstat,
124 };
125 
126 char	Eperm[] =	"permission denied";
127 char	Enotdir[] =	"not a directory";
128 char	Enoauth[] =	"ramfs: authentication not required";
129 char	Enotexist[] =	"file does not exist";
130 char	Einuse[] =	"file in use";
131 char	Eexist[] =	"file exists";
132 char	Eisdir[] =	"file is a directory";
133 char	Enotowner[] =	"not owner";
134 char	Eisopen[] = 	"file already open for I/O";
135 char	Excl[] = 	"exclusive use file already open";
136 char	Ename[] = 	"illegal name";
137 char	Eversion[] =	"unknown 9P version";
138 char	Enotempty[] =	"directory not empty";
139 
140 int debug;
141 int private;
142 
143 static int memlim = 1;
144 
145 void
notifyf(void * a,char * s)146 notifyf(void *a, char *s)
147 {
148 	USED(a);
149 	if(strncmp(s, "interrupt", 9) == 0)
150 		noted(NCONT);
151 	noted(NDFLT);
152 }
153 
154 void
main(int argc,char * argv[])155 main(int argc, char *argv[])
156 {
157 	Ram *r;
158 	char *defmnt, *service;
159 	int p[2];
160 	int fd;
161 	int stdio = 0;
162 
163 	service = "ramfs";
164 	defmnt = "/tmp";
165 	ARGBEGIN{
166 	case 'i':
167 		defmnt = 0;
168 		stdio = 1;
169 		mfd[0] = 0;
170 		mfd[1] = 1;
171 		break;
172 	case 'm':
173 		defmnt = EARGF(usage());
174 		break;
175 	case 'p':
176 		private++;
177 		break;
178 	case 's':
179 		defmnt = 0;
180 		break;
181 	case 'u':
182 		memlim = 0;		/* unlimited memory consumption */
183 		break;
184 	case 'D':
185 		debug = 1;
186 		break;
187 	case 'S':
188 		defmnt = 0;
189 		service = EARGF(usage());
190 		break;
191 	default:
192 		usage();
193 	}ARGEND
194 
195 	if(pipe(p) < 0)
196 		error("pipe failed");
197 	if(!stdio){
198 		mfd[0] = p[0];
199 		mfd[1] = p[0];
200 		if(defmnt == 0){
201 			char buf[64];
202 			snprint(buf, sizeof buf, "#s/%s", service);
203 			fd = create(buf, OWRITE|ORCLOSE, 0666);
204 			if(fd < 0)
205 				error("create failed");
206 			sprint(buf, "%d", p[1]);
207 			if(write(fd, buf, strlen(buf)) < 0)
208 				error("writing service file");
209 		}
210 	}
211 
212 	user = getuser();
213 	notify(notifyf);
214 	ram = emalloc(maxnram*sizeof(Ram));
215 	nram = 1;
216 	r = &ram[0];
217 	r->busy = 1;
218 	r->data = 0;
219 	r->ndata = 0;
220 	r->perm = DMDIR | 0775;
221 	r->qid.type = QTDIR;
222 	r->qid.path = 0LL;
223 	r->qid.vers = 0;
224 	r->parent = 0;
225 	r->user = user;
226 	r->group = user;
227 	r->muid = user;
228 	r->atime = time(0);
229 	r->mtime = r->atime;
230 	r->name = estrdup(".");
231 
232 	if(debug) {
233 		fmtinstall('F', fcallfmt);
234 		fmtinstall('M', dirmodefmt);
235 	}
236 	switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
237 	case -1:
238 		error("fork");
239 	case 0:
240 		close(p[1]);
241 		io();
242 		break;
243 	default:
244 		close(p[0]);	/* don't deadlock if child fails */
245 		if(defmnt && mount(p[1], -1, defmnt, MREPL|MCREATE, "") < 0)
246 			error("mount failed");
247 	}
248 	exits(0);
249 }
250 
251 char*
rversion(Fid *)252 rversion(Fid*)
253 {
254 	Fid *f;
255 
256 	for(f = fids; f; f = f->next)
257 		if(f->busy)
258 			rclunk(f);
259 	if(thdr.msize > sizeof mdata)
260 		rhdr.msize = sizeof mdata;
261 	else
262 		rhdr.msize = thdr.msize;
263 	messagesize = rhdr.msize;
264 	if(strncmp(thdr.version, "9P2000", 6) != 0)
265 		return Eversion;
266 	rhdr.version = "9P2000";
267 	return 0;
268 }
269 
270 char*
rauth(Fid *)271 rauth(Fid*)
272 {
273 	return "ramfs: no authentication required";
274 }
275 
276 char*
rflush(Fid * f)277 rflush(Fid *f)
278 {
279 	USED(f);
280 	return 0;
281 }
282 
283 char*
rattach(Fid * f)284 rattach(Fid *f)
285 {
286 	/* no authentication! */
287 	f->busy = 1;
288 	f->rclose = 0;
289 	f->ram = &ram[0];
290 	rhdr.qid = f->ram->qid;
291 	if(thdr.uname[0])
292 		f->user = estrdup(thdr.uname);
293 	else
294 		f->user = "none";
295 	if(strcmp(user, "none") == 0)
296 		user = f->user;
297 	return 0;
298 }
299 
300 char*
clone(Fid * f,Fid ** nf)301 clone(Fid *f, Fid **nf)
302 {
303 	if(f->open)
304 		return Eisopen;
305 	if(f->ram->busy == 0)
306 		return Enotexist;
307 	*nf = newfid(thdr.newfid);
308 	(*nf)->busy = 1;
309 	(*nf)->open = 0;
310 	(*nf)->rclose = 0;
311 	(*nf)->ram = f->ram;
312 	(*nf)->user = f->user;	/* no ref count; the leakage is minor */
313 	return 0;
314 }
315 
316 char*
rwalk(Fid * f)317 rwalk(Fid *f)
318 {
319 	Ram *r, *fram;
320 	char *name;
321 	Ram *parent;
322 	Fid *nf;
323 	char *err;
324 	ulong t;
325 	int i;
326 
327 	err = nil;
328 	nf = nil;
329 	rhdr.nwqid = 0;
330 	if(thdr.newfid != thdr.fid){
331 		err = clone(f, &nf);
332 		if(err)
333 			return err;
334 		f = nf;	/* walk the new fid */
335 	}
336 	fram = f->ram;
337 	if(thdr.nwname > 0){
338 		t = time(0);
339 		for(i=0; i<thdr.nwname && i<MAXWELEM; i++){
340 			if((fram->qid.type & QTDIR) == 0){
341 				err = Enotdir;
342  				break;
343 			}
344 			if(fram->busy == 0){
345 				err = Enotexist;
346 				break;
347 			}
348 			fram->atime = t;
349 			name = thdr.wname[i];
350 			if(strcmp(name, ".") == 0){
351     Found:
352 				rhdr.nwqid++;
353 				rhdr.wqid[i] = fram->qid;
354 				continue;
355 			}
356 			parent = &ram[fram->parent];
357 			if(!perm(f, parent, Pexec)){
358 				err = Eperm;
359 				break;
360 			}
361 			if(strcmp(name, "..") == 0){
362 				fram = parent;
363 				goto Found;
364 			}
365 			for(r=ram; r < &ram[nram]; r++)
366 				if(r->busy && r->parent==fram-ram && strcmp(name, r->name)==0){
367 					fram = r;
368 					goto Found;
369 				}
370 			break;
371 		}
372 		if(i==0 && err == nil)
373 			err = Enotexist;
374 	}
375 	if(nf != nil && (err!=nil || rhdr.nwqid<thdr.nwname)){
376 		/* clunk the new fid, which is the one we walked */
377 		f->busy = 0;
378 		f->ram = nil;
379 	}
380 	if(rhdr.nwqid > 0)
381 		err = nil;	/* didn't get everything in 9P2000 right! */
382 	if(rhdr.nwqid == thdr.nwname)	/* update the fid after a successful walk */
383 		f->ram = fram;
384 	return err;
385 }
386 
387 char *
ropen(Fid * f)388 ropen(Fid *f)
389 {
390 	Ram *r;
391 	int mode, trunc;
392 
393 	if(f->open)
394 		return Eisopen;
395 	r = f->ram;
396 	if(r->busy == 0)
397 		return Enotexist;
398 	if(r->perm & DMEXCL)
399 		if(r->open)
400 			return Excl;
401 	mode = thdr.mode;
402 	if(r->qid.type & QTDIR){
403 		if(mode != OREAD)
404 			return Eperm;
405 		rhdr.qid = r->qid;
406 		return 0;
407 	}
408 	if(mode & ORCLOSE){
409 		/* can't remove root; must be able to write parent */
410 		if(r->qid.path==0 || !perm(f, &ram[r->parent], Pwrite))
411 			return Eperm;
412 		f->rclose = 1;
413 	}
414 	trunc = mode & OTRUNC;
415 	mode &= OPERM;
416 	if(mode==OWRITE || mode==ORDWR || trunc)
417 		if(!perm(f, r, Pwrite))
418 			return Eperm;
419 	if(mode==OREAD || mode==ORDWR)
420 		if(!perm(f, r, Pread))
421 			return Eperm;
422 	if(mode==OEXEC)
423 		if(!perm(f, r, Pexec))
424 			return Eperm;
425 	if(trunc && (r->perm&DMAPPEND)==0){
426 		r->ndata = 0;
427 		if(r->data)
428 			free(r->data);
429 		r->data = 0;
430 		r->qid.vers++;
431 	}
432 	rhdr.qid = r->qid;
433 	rhdr.iounit = messagesize-IOHDRSZ;
434 	f->open = 1;
435 	r->open++;
436 	return 0;
437 }
438 
439 char *
rcreate(Fid * f)440 rcreate(Fid *f)
441 {
442 	Ram *r;
443 	char *name;
444 	long parent, prm;
445 
446 	if(f->open)
447 		return Eisopen;
448 	if(f->ram->busy == 0)
449 		return Enotexist;
450 	parent = f->ram - ram;
451 	if((f->ram->qid.type&QTDIR) == 0)
452 		return Enotdir;
453 	/* must be able to write parent */
454 	if(!perm(f, f->ram, Pwrite))
455 		return Eperm;
456 	prm = thdr.perm;
457 	name = thdr.name;
458 	if(strcmp(name, ".")==0 || strcmp(name, "..")==0)
459 		return Ename;
460 	for(r=ram; r<&ram[nram]; r++)
461 		if(r->busy && parent==r->parent)
462 		if(strcmp((char*)name, r->name)==0)
463 			return Einuse;
464 	for(r=ram; r->busy; r++)
465 		if(r == &ram[maxnram-1] && (r = ramexpand(r)) == nil)
466 			return "no free ram resources";
467 	r->busy = 1;
468 	r->qid.path = ++path;
469 	r->qid.vers = 0;
470 	if(prm & DMDIR)
471 		r->qid.type |= QTDIR;
472 	r->parent = parent;
473 	free(r->name);
474 	r->name = estrdup(name);
475 	r->user = f->user;
476 	r->group = f->ram->group;
477 	r->muid = f->ram->muid;
478 	if(prm & DMDIR)
479 		prm = (prm&~0777) | (f->ram->perm&prm&0777);
480 	else
481 		prm = (prm&(~0777|0111)) | (f->ram->perm&prm&0666);
482 	r->perm = prm;
483 	r->ndata = 0;
484 	if(r-ram >= nram)
485 		nram = r - ram + 1;
486 	r->atime = time(0);
487 	r->mtime = r->atime;
488 	f->ram->mtime = r->atime;
489 	f->ram = r;
490 	rhdr.qid = r->qid;
491 	rhdr.iounit = messagesize-IOHDRSZ;
492 	f->open = 1;
493 	if(thdr.mode & ORCLOSE)
494 		f->rclose = 1;
495 	r->open = 1;
496 	return 0;
497 }
498 
499 char*
rread(Fid * f)500 rread(Fid *f)
501 {
502 	Ram *r;
503 	uchar *buf;
504 	vlong off;
505 	int n, m, cnt;
506 
507 	if(f->ram->busy == 0)
508 		return Enotexist;
509 	n = 0;
510 	rhdr.count = 0;
511 	rhdr.data = (char*)rdata;
512 	if (thdr.offset < 0)
513 		return "negative seek offset";
514 	off = thdr.offset;
515 	buf = rdata;
516 	cnt = thdr.count;
517 	if(cnt > messagesize)	/* shouldn't happen, anyway */
518 		cnt = messagesize;
519 	if(cnt < 0)
520 		return "negative read count";
521 	if(f->ram->qid.type & QTDIR){
522 		for(r=ram+1; off > 0; r++){
523 			if(r->busy && r->parent==f->ram-ram)
524 				off -= ramstat(r, statbuf, sizeof statbuf);
525 			if(r == &ram[nram-1])
526 				return 0;
527 		}
528 		for(; r<&ram[nram] && n < cnt; r++){
529 			if(!r->busy || r->parent!=f->ram-ram)
530 				continue;
531 			m = ramstat(r, buf+n, cnt-n);
532 			if(m == 0)
533 				break;
534 			n += m;
535 		}
536 		rhdr.data = (char*)rdata;
537 		rhdr.count = n;
538 		return 0;
539 	}
540 	r = f->ram;
541 	if(off >= r->ndata)
542 		return 0;
543 	r->atime = time(0);
544 	n = cnt;
545 	if(off+n > r->ndata)
546 		n = r->ndata - off;
547 	rhdr.data = r->data+off;
548 	rhdr.count = n;
549 	return 0;
550 }
551 
552 char*
rwrite(Fid * f)553 rwrite(Fid *f)
554 {
555 	Ram *r;
556 	vlong off;
557 	int cnt;
558 
559 	r = f->ram;
560 	rhdr.count = 0;
561 	if(r->busy == 0)
562 		return Enotexist;
563 	if (thdr.offset < 0)
564 		return "negative seek offset";
565 	off = thdr.offset;
566 	if(r->perm & DMAPPEND)
567 		off = r->ndata;
568 	cnt = thdr.count;
569 	if(cnt < 0)
570 		return "negative write count";
571 	if(r->qid.type & QTDIR)
572 		return Eisdir;
573 	if(memlim && off+cnt >= Maxsize)		/* sanity check */
574 		return "write too big";
575 	if(off+cnt > r->ndata)
576 		r->data = erealloc(r->data, off+cnt);
577 	if(off > r->ndata)
578 		memset(r->data+r->ndata, 0, off-r->ndata);
579 	if(off+cnt > r->ndata)
580 		r->ndata = off+cnt;
581 	memmove(r->data+off, thdr.data, cnt);
582 	r->qid.vers++;
583 	r->mtime = time(0);
584 	rhdr.count = cnt;
585 	return 0;
586 }
587 
588 static int
emptydir(Ram * dr)589 emptydir(Ram *dr)
590 {
591 	long didx = dr - ram;
592 	Ram *r;
593 
594 	for(r=ram; r<&ram[nram]; r++)
595 		if(r->busy && didx==r->parent)
596 			return 0;
597 	return 1;
598 }
599 
600 char *
realremove(Ram * r)601 realremove(Ram *r)
602 {
603 	if(r->qid.type & QTDIR && !emptydir(r))
604 		return Enotempty;
605 	r->ndata = 0;
606 	if(r->data)
607 		free(r->data);
608 	r->data = 0;
609 	r->parent = 0;
610 	memset(&r->qid, 0, sizeof r->qid);
611 	free(r->name);
612 	r->name = nil;
613 	r->busy = 0;
614 	return nil;
615 }
616 
617 char *
rclunk(Fid * f)618 rclunk(Fid *f)
619 {
620 	char *e = nil;
621 
622 	if(f->open)
623 		f->ram->open--;
624 	if(f->rclose)
625 		e = realremove(f->ram);
626 	f->busy = 0;
627 	f->open = 0;
628 	f->ram = 0;
629 	return e;
630 }
631 
632 char *
rremove(Fid * f)633 rremove(Fid *f)
634 {
635 	Ram *r;
636 
637 	if(f->open)
638 		f->ram->open--;
639 	f->busy = 0;
640 	f->open = 0;
641 	r = f->ram;
642 	f->ram = 0;
643 	if(r->busy == 0)
644 		return Enotexist;
645 	if(r->qid.path == 0 || !perm(f, &ram[r->parent], Pwrite))
646 		return Eperm;
647 	ram[r->parent].mtime = time(0);
648 	return realremove(r);
649 }
650 
651 char *
rstat(Fid * f)652 rstat(Fid *f)
653 {
654 	if(f->ram->busy == 0)
655 		return Enotexist;
656 	rhdr.nstat = ramstat(f->ram, statbuf, sizeof statbuf);
657 	rhdr.stat = statbuf;
658 	return 0;
659 }
660 
661 char *
rwstat(Fid * f)662 rwstat(Fid *f)
663 {
664 	Ram *r, *s;
665 	Dir dir;
666 
667 	if(f->ram->busy == 0)
668 		return Enotexist;
669 	convM2D(thdr.stat, thdr.nstat, &dir, (char*)statbuf);
670 	r = f->ram;
671 
672 	/*
673 	 * To change length, must have write permission on file.
674 	 */
675 	if(dir.length!=~0 && dir.length!=r->ndata){
676 	 	if(!perm(f, r, Pwrite))
677 			return Eperm;
678 	}
679 
680 	/*
681 	 * To change name, must have write permission in parent
682 	 * and name must be unique.
683 	 */
684 	if(dir.name[0]!='\0' && strcmp(dir.name, r->name)!=0){
685 	 	if(!perm(f, &ram[r->parent], Pwrite))
686 			return Eperm;
687 		for(s=ram; s<&ram[nram]; s++)
688 			if(s->busy && s->parent==r->parent)
689 			if(strcmp(dir.name, s->name)==0)
690 				return Eexist;
691 	}
692 
693 	/*
694 	 * To change mode or mtime, must be owner or group leader.
695 	 * Because of lack of users file, leader=>group itself.
696 	 */
697 	if(dir.mode!=~0 && r->perm!=dir.mode ||
698 	   dir.mtime!=~0 && dir.mtime!=r->mtime){
699 		if(strcmp(f->user, r->user) != 0)
700 		if(strcmp(f->user, r->group) != 0)
701 			return Enotowner;
702 	}
703 
704 	/*
705 	 * To change group, must be owner and member of new group,
706 	 * or leader of current group and leader of new group.
707 	 * Second case cannot happen, but we check anyway.
708 	 */
709 	if(dir.gid[0]!='\0' && strcmp(r->group, dir.gid)!=0){
710 		if(strcmp(f->user, r->user) == 0)
711 	//	if(strcmp(f->user, dir.gid) == 0)
712 			goto ok;
713 		if(strcmp(f->user, r->group) == 0)
714 		if(strcmp(f->user, dir.gid) == 0)
715 			goto ok;
716 		return Enotowner;
717 		ok:;
718 	}
719 
720 	/* all ok; do it */
721 	if(dir.mode != ~0){
722 		dir.mode &= ~DMDIR;	/* cannot change dir bit */
723 		dir.mode |= r->perm&DMDIR;
724 		r->perm = dir.mode;
725 	}
726 	if(dir.mtime != ~0)
727 		r->mtime = dir.mtime;
728 	if(dir.name[0] != '\0'){
729 		free(r->name);
730 		r->name = estrdup(dir.name);
731 	}
732 	if(dir.gid[0] != '\0')
733 		r->group = estrdup(dir.gid);
734 	if(dir.length!=~0 && dir.length!=r->ndata){
735 		r->data = erealloc(r->data, dir.length);
736 		if(r->ndata < dir.length)
737 			memset(r->data+r->ndata, 0, dir.length-r->ndata);
738 		r->ndata = dir.length;
739 		r->qid.vers++;
740 	}
741 	ram[r->parent].mtime = time(0);
742 	return 0;
743 }
744 
745 uint
ramstat(Ram * r,uchar * buf,uint nbuf)746 ramstat(Ram *r, uchar *buf, uint nbuf)
747 {
748 	int n;
749 	Dir dir;
750 
751 	dir.name = r->name;
752 	dir.qid = r->qid;
753 	dir.mode = r->perm;
754 	dir.length = r->ndata;
755 	dir.uid = r->user;
756 	dir.gid = r->group;
757 	dir.muid = r->muid;
758 	dir.atime = r->atime;
759 	dir.mtime = r->mtime;
760 	n = convD2M(&dir, buf, nbuf);
761 	if(n > 2)
762 		return n;
763 	return 0;
764 }
765 
766 Fid *
newfid(int fid)767 newfid(int fid)
768 {
769 	Fid *f, *ff;
770 
771 	ff = 0;
772 	for(f = fids; f; f = f->next)
773 		if(f->fid == fid)
774 			return f;
775 		else if(!ff && !f->busy)
776 			ff = f;
777 	if(ff){
778 		ff->fid = fid;
779 		return ff;
780 	}
781 	f = emalloc(sizeof *f);
782 	f->ram = nil;
783 	f->fid = fid;
784 	f->next = fids;
785 	fids = f;
786 	return f;
787 }
788 
789 void
io(void)790 io(void)
791 {
792 	char *err, buf[40];
793 	int n, pid, ctl;
794 	Fid *fid;
795 
796 	pid = getpid();
797 	if(private){
798 		snprint(buf, sizeof buf, "/proc/%d/ctl", pid);
799 		ctl = open(buf, OWRITE);
800 		if(ctl < 0){
801 			fprint(2, "can't protect ramfs\n");
802 		}else{
803 			fprint(ctl, "noswap\n");
804 			fprint(ctl, "private\n");
805 			close(ctl);
806 		}
807 	}
808 
809 	for(;;){
810 		/*
811 		 * reading from a pipe or a network device
812 		 * will give an error after a few eof reads.
813 		 * however, we cannot tell the difference
814 		 * between a zero-length read and an interrupt
815 		 * on the processes writing to us,
816 		 * so we wait for the error.
817 		 */
818 		n = read9pmsg(mfd[0], mdata, messagesize);
819 		if(n < 0){
820 			rerrstr(buf, sizeof buf);
821 			if(buf[0]=='\0' || strstr(buf, "hungup"))
822 				exits("");
823 			error("mount read");
824 		}
825 		if(n == 0)
826 			continue;
827 		if(convM2S(mdata, n, &thdr) == 0)
828 			continue;
829 
830 		if(debug)
831 			fprint(2, "ramfs %d:<-%F\n", pid, &thdr);
832 
833 		if(thdr.type<0 || thdr.type>=nelem(fcalls) || !fcalls[thdr.type])
834 			err = "bad fcall type";
835 		else if(((fid=newfid(thdr.fid))==nil || !fid->ram) && needfid[thdr.type])
836 			err = "fid not in use";
837 		else
838 			err = (*fcalls[thdr.type])(fid);
839 		if(err){
840 			rhdr.type = Rerror;
841 			rhdr.ename = err;
842 		}else{
843 			rhdr.type = thdr.type + 1;
844 			rhdr.fid = thdr.fid;
845 		}
846 		rhdr.tag = thdr.tag;
847 		if(debug)
848 			fprint(2, "ramfs %d:->%F\n", pid, &rhdr);/**/
849 		n = convS2M(&rhdr, mdata, messagesize);
850 		if(n == 0)
851 			error("convS2M error on write");
852 		if(write(mfd[1], mdata, n) != n)
853 			error("mount write");
854 	}
855 }
856 
857 int
perm(Fid * f,Ram * r,int p)858 perm(Fid *f, Ram *r, int p)
859 {
860 	if((p*Pother) & r->perm)
861 		return 1;
862 	if(strcmp(f->user, r->group)==0 && ((p*Pgroup) & r->perm))
863 		return 1;
864 	if(strcmp(f->user, r->user)==0 && ((p*Powner) & r->perm))
865 		return 1;
866 	return 0;
867 }
868 
869 Ram*
ramexpand(Ram * r)870 ramexpand(Ram *r)
871 {
872 	Ram *newram;
873 	Fid *f;
874 	uintptr offs;
875 
876 	newram = (Ram*)realloc(ram, (maxnram+Nram)*sizeof(Ram));
877 	if(newram == nil)
878 		return nil;
879 	memset(newram + maxnram, 0, Nram*sizeof(Ram));
880 	offs = (uintptr)newram - (uintptr)ram;
881 	for(f = fids; f; f = f->next)
882 		if(f->busy && f->ram != nil)
883 			f->ram = (Ram*)((uintptr)f->ram + offs);
884 	maxnram += Nram;
885 	ram = newram;
886 	return (Ram*)((uintptr)r + offs);
887 }
888 
889 void
error(char * s)890 error(char *s)
891 {
892 	fprint(2, "%s: %s: %r\n", argv0, s);
893 	exits(s);
894 }
895 
896 void *
emalloc(ulong n)897 emalloc(ulong n)
898 {
899 	void *p;
900 
901 	p = malloc(n);
902 	if(!p)
903 		error("out of memory");
904 	memset(p, 0, n);
905 	return p;
906 }
907 
908 void *
erealloc(void * p,ulong n)909 erealloc(void *p, ulong n)
910 {
911 	p = realloc(p, n);
912 	if(n != 0 && !p)
913 		error("out of memory");
914 	return p;
915 }
916 
917 char *
estrdup(char * q)918 estrdup(char *q)
919 {
920 	char *p;
921 	int n;
922 
923 	n = strlen(q)+1;
924 	p = malloc(n);
925 	if(!p)
926 		error("out of memory");
927 	memmove(p, q, n);
928 	return p;
929 }
930 
931 void
usage(void)932 usage(void)
933 {
934 	fprint(2, "usage: %s [-Dipsu] [-m mountpoint] [-S srvname]\n", argv0);
935 	exits("usage");
936 }
937