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