Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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