Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <authsrv.h>
4
#include <fcall.h>
5
#include "tapefs.h"
6
 
7
Fid	*fids;
8
Ram	*ram;
9
int	mfd[2];
10
char	*user;
11
uchar	mdata[Maxbuf+IOHDRSZ];
12
int	messagesize = Maxbuf+IOHDRSZ;
13
Fcall	rhdr;
14
Fcall	thdr;
15
ulong	path;
16
Idmap	*uidmap;
17
Idmap	*gidmap;
18
int	replete;
19
int	blocksize;		/* for 32v */
20
int	verbose;
21
int	newtap;		/* tap with time in sec */
22
int	blocksize;
23
 
24
Fid *	newfid(int);
25
int	ramstat(Ram*, uchar*, int);
26
void	io(void);
27
void	usage(void);
28
int	perm(int);
29
 
30
char	*rflush(Fid*), *rversion(Fid*), *rauth(Fid*),
31
	*rattach(Fid*), *rwalk(Fid*),
32
	*ropen(Fid*), *rcreate(Fid*),
33
	*rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
34
	*rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
35
 
36
char 	*(*fcalls[])(Fid*) = {
37
	[Tflush]	rflush,
38
	[Tversion]		rversion,
39
	[Tauth]	rauth,
40
	[Tattach]	rattach,
41
	[Twalk]		rwalk,
42
	[Topen]		ropen,
43
	[Tcreate]	rcreate,
44
	[Tread]		rread,
45
	[Twrite]	rwrite,
46
	[Tclunk]	rclunk,
47
	[Tremove]	rremove,
48
	[Tstat]		rstat,
49
	[Twstat]	rwstat,
50
};
51
 
52
char	Eperm[] =	"permission denied";
53
char	Enotdir[] =	"not a directory";
54
char	Enoauth[] =	"tapefs: authentication not required";
55
char	Enotexist[] =	"file does not exist";
56
char	Einuse[] =	"file in use";
57
char	Eexist[] =	"file exists";
58
char	Enotowner[] =	"not owner";
59
char	Eisopen[] = 	"file already open for I/O";
60
char	Excl[] = 	"exclusive use file already open";
61
char	Ename[] = 	"illegal name";
62
 
63
void
64
notifyf(void *a, char *s)
65
{
66
	USED(a);
67
	if(strncmp(s, "interrupt", 9) == 0)
68
		noted(NCONT);
69
	noted(NDFLT);
70
}
71
 
72
void
73
main(int argc, char *argv[])
74
{
75
	Ram *r;
76
	char *defmnt;
77
	int p[2];
78
	char buf[TICKREQLEN];
79
 
80
	fmtinstall('F', fcallfmt);
81
 
82
	defmnt = "/n/tapefs";
83
	ARGBEGIN{
84
	case 'm':
85
		defmnt = EARGF(usage());
86
		break;
87
	case 'p':			/* password file */
88
		uidmap = getpass(EARGF(usage()));
89
		break;
90
	case 'g':			/* group file */
91
		gidmap = getpass(EARGF(usage()));
92
		break;
93
	case 'v':
94
		verbose++;
95
		break;
96
	case 'n':
97
		newtap++;
98
		break;
99
	case 'b':
100
		blocksize = atoi(EARGF(usage()));
101
		break;
102
	default:
103
		usage();
104
	}ARGEND
105
 
106
	if(argc==0)
107
		error("no file to mount");
108
	user = getuser();
109
	if(user == nil)
110
		user = "dmr";
111
	ram = r = (Ram *)emalloc(sizeof(Ram));
112
	r->busy = 1;
113
	r->data = 0;
114
	r->ndata = 0;
115
	r->perm = DMDIR | 0775;
116
	r->qid.path = 0;
117
	r->qid.vers = 0;
118
	r->qid.type = QTDIR;
119
	r->parent = 0;
120
	r->child = 0;
121
	r->next = 0;
122
	r->user = user;
123
	r->group = user;
124
	r->atime = time(0);
125
	r->mtime = r->atime;
126
	r->replete = 0;
127
	r->name = estrdup(".");
128
	populate(argv[0]);
129
	r->replete |= replete;
130
	if(pipe(p) < 0)
131
		error("pipe failed");
132
	mfd[0] = mfd[1] = p[0];
133
	notify(notifyf);
134
 
135
	switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
136
	case -1:
137
		error("fork");
138
	case 0:
139
		close(p[1]);
140
		notify(notifyf);
141
		io();
142
		break;
143
	default:
144
		close(p[0]);	/* don't deadlock if child fails */
145
		if(mount(p[1], -1, defmnt, MREPL|MCREATE, "") < 0) {
146
			sprint(buf, "mount on `%s' failed", defmnt);
147
			error(buf);
148
		}
149
	}
150
	exits(0);
151
}
152
 
153
char*
154
rversion(Fid *unused)
155
{
156
	Fid *f;
157
 
158
	USED(unused);
159
 
160
	if(rhdr.msize < 256)
161
		return "version: message too small";
162
	if(rhdr.msize > messagesize)
163
		rhdr.msize = messagesize;
164
	else
165
		messagesize = rhdr.msize;
166
	thdr.msize = messagesize;
167
	if(strncmp(rhdr.version, "9P2000", 6) != 0)
168
		return "unrecognized 9P version";
169
	thdr.version = "9P2000";
170
 
171
	for(f = fids; f; f = f->next)
172
		if(f->busy)
173
			rclunk(f);
174
	return 0;
175
}
176
 
177
char*
178
rauth(Fid *unused)
179
{
180
	USED(unused);
181
 
182
	return Enoauth;
183
}
184
 
185
char*
186
rflush(Fid *f)
187
{
188
	USED(f);
189
	return 0;
190
}
191
 
192
char*
193
rattach(Fid *f)
194
{
195
	/* no authentication! */
196
	f->busy = 1;
197
	f->rclose = 0;
198
	f->ram = ram;
199
	thdr.qid = f->ram->qid;
200
	if(rhdr.uname[0])
201
		f->user = strdup(rhdr.uname);
202
	else
203
		f->user = "none";
204
	return 0;
205
}
206
 
207
char*
208
rwalk(Fid *f)
209
{
210
	Fid *nf;
211
	Ram *r;
212
	char *err;
213
	char *name;
214
	Ram *dir;
215
	int i;
216
 
217
	nf = nil;
218
	if(f->ram->busy == 0)
219
		return Enotexist;
220
	if(f->open)
221
		return Eisopen;
222
	if(rhdr.newfid != rhdr.fid){
223
		nf = newfid(rhdr.newfid);
224
		nf->busy = 1;
225
		nf->open = 0;
226
		nf->rclose = 0;
227
		nf->ram = f->ram;
228
		nf->user = f->user;	/* no ref count; the leakage is minor */
229
		f = nf;
230
	}
231
 
232
	thdr.nwqid = 0;
233
	err = nil;
234
	r = f->ram;
235
 
236
	if(rhdr.nwname > 0){
237
		for(i=0; i<rhdr.nwname; i++){
238
			if((r->qid.type & QTDIR) == 0){
239
				err = Enotdir;
240
				break;
241
			}
242
			if(r->busy == 0){
243
				err = Enotexist;
244
				break;
245
			}
246
			r->atime = time(0);
247
			name = rhdr.wname[i];
248
			dir = r;
249
			if(!perm(Pexec)){
250
				err = Eperm;
251
				break;
252
			}
253
			if(strcmp(name, "..") == 0){
254
				r = dir->parent;
255
   Accept:
256
				if(i == MAXWELEM){
257
					err = "name too long";
258
					break;
259
				}
260
 				thdr.wqid[thdr.nwqid++] = r->qid;
261
				continue;
262
			}
263
			if(!dir->replete)
264
				popdir(dir);
265
			for(r=dir->child; r; r=r->next)
266
				if(r->busy && strcmp(name, r->name)==0)
267
					goto Accept;
268
			break;	/* file not found */
269
		}
270
 
271
		if(i==0 && err == nil)
272
			err = Enotexist;
273
	}
274
 
275
	if(err!=nil || thdr.nwqid<rhdr.nwname){
276
		if(nf){
277
			nf->busy = 0;
278
			nf->open = 0;
279
			nf->ram = 0;
280
		}
281
	}else if(thdr.nwqid  == rhdr.nwname)
282
		f->ram = r;
283
 
284
	return err;
285
 
286
}
287
 
288
char *
289
ropen(Fid *f)
290
{
291
	Ram *r;
292
	int mode, trunc;
293
 
294
	if(f->open)
295
		return Eisopen;
296
	r = f->ram;
297
	if(r->busy == 0)
298
		return Enotexist;
299
	if(r->perm & DMEXCL)
300
		if(r->open)
301
			return Excl;
302
	mode = rhdr.mode;
303
	if(r->qid.type & QTDIR){
304
		if(mode != OREAD)
305
			return Eperm;
306
		thdr.qid = r->qid;
307
		return 0;
308
	}
309
	if(mode & ORCLOSE)
310
		return Eperm;
311
	trunc = mode & OTRUNC;
312
	mode &= OPERM;
313
	if(mode==OWRITE || mode==ORDWR || trunc)
314
		if(!perm(Pwrite))
315
			return Eperm;
316
	if(mode==OREAD || mode==ORDWR)
317
		if(!perm(Pread))
318
			return Eperm;
319
	if(mode==OEXEC)
320
		if(!perm(Pexec))
321
			return Eperm;
322
	if(trunc && (r->perm&DMAPPEND)==0){
323
		r->ndata = 0;
324
		dotrunc(r);
325
		r->qid.vers++;
326
	}
327
	thdr.qid = r->qid;
328
	thdr.iounit = messagesize-IOHDRSZ;
329
	f->open = 1;
330
	r->open++;
331
	return 0;
332
}
333
 
334
char *
335
rcreate(Fid *f)
336
{
337
	USED(f);
338
 
339
	return Eperm;
340
}
341
 
342
char*
343
rread(Fid *f)
344
{
345
	int i, len;
346
	Ram *r;
347
	char *buf;
348
	uvlong off, end;
349
	int n, cnt;
350
 
351
	if(f->ram->busy == 0)
352
		return Enotexist;
353
	n = 0;
354
	thdr.count = 0;
355
	off = rhdr.offset;
356
	end = rhdr.offset + rhdr.count;
357
	cnt = rhdr.count;
358
	if(cnt > messagesize-IOHDRSZ)
359
		cnt = messagesize-IOHDRSZ;
360
	buf = thdr.data;
361
	if(f->ram->qid.type & QTDIR){
362
		if(!f->ram->replete)
363
			popdir(f->ram);
364
		for(i=0,r=f->ram->child; r!=nil && i<end; r=r->next){
365
			if(!r->busy)
366
				continue;
367
			len = ramstat(r, (uchar*)buf+n, cnt-n);
368
			if(len <= BIT16SZ)
369
				break;
370
			if(i >= off)
371
				n += len;
372
			i += len;
373
		}
374
		thdr.count = n;
375
		return 0;
376
	}
377
	r = f->ram;
378
	if(off >= r->ndata)
379
		return 0;
380
	r->atime = time(0);
381
	n = cnt;
382
	if(off+n > r->ndata)
383
		n = r->ndata - off;
384
	thdr.data = doread(r, off, n);
385
	thdr.count = n;
386
	return 0;
387
}
388
 
389
char*
390
rwrite(Fid *f)
391
{
392
	Ram *r;
393
	ulong off;
394
	int cnt;
395
 
396
	r = f->ram;
397
	if(dopermw(f->ram)==0)
398
		return Eperm;
399
	if(r->busy == 0)
400
		return Enotexist;
401
	off = rhdr.offset;
402
	if(r->perm & DMAPPEND)
403
		off = r->ndata;
404
	cnt = rhdr.count;
405
	if(r->qid.type & QTDIR)
406
		return "file is a directory";
407
	if(off > 100*1024*1024)		/* sanity check */
408
		return "write too big";
409
	dowrite(r, rhdr.data, off, cnt);
410
	r->qid.vers++;
411
	r->mtime = time(0);
412
	thdr.count = cnt;
413
	return 0;
414
}
415
 
416
char *
417
rclunk(Fid *f)
418
{
419
	if(f->open)
420
		f->ram->open--;
421
	f->busy = 0;
422
	f->open = 0;
423
	f->ram = 0;
424
	return 0;
425
}
426
 
427
char *
428
rremove(Fid *f)
429
{
430
	USED(f);
431
	return Eperm;
432
}
433
 
434
char *
435
rstat(Fid *f)
436
{
437
	if(f->ram->busy == 0)
438
		return Enotexist;
439
	thdr.nstat = ramstat(f->ram, thdr.stat, messagesize-IOHDRSZ);
440
	return 0;
441
}
442
 
443
char *
444
rwstat(Fid *f)
445
{
446
	if(f->ram->busy == 0)
447
		return Enotexist;
448
	return Eperm;
449
}
450
 
451
int
452
ramstat(Ram *r, uchar *buf, int nbuf)
453
{
454
	Dir dir;
455
 
456
	dir.name = r->name;
457
	dir.qid = r->qid;
458
	dir.mode = r->perm;
459
	dir.length = r->ndata;
460
	dir.uid = r->user;
461
	dir.gid = r->group;
462
	dir.muid = r->user;
463
	dir.atime = r->atime;
464
	dir.mtime = r->mtime;
465
	return convD2M(&dir, buf, nbuf);
466
}
467
 
468
Fid *
469
newfid(int fid)
470
{
471
	Fid *f, *ff;
472
 
473
	ff = 0;
474
	for(f = fids; f; f = f->next)
475
		if(f->fid == fid)
476
			return f;
477
		else if(!ff && !f->busy)
478
			ff = f;
479
	if(ff){
480
		ff->fid = fid;
481
		ff->open = 0;
482
		ff->busy = 1;
483
	}
484
	f = emalloc(sizeof *f);
485
	f->ram = 0;
486
	f->fid = fid;
487
	f->busy = 1;
488
	f->open = 0;
489
	f->next = fids;
490
	fids = f;
491
	return f;
492
}
493
 
494
void
495
io(void)
496
{
497
	char *err;
498
	int n, nerr;
499
	char buf[ERRMAX];
500
 
501
	errstr(buf, sizeof buf);
502
	for(nerr=0, buf[0]='\0'; nerr<100; nerr++){
503
		/*
504
		 * reading from a pipe or a network device
505
		 * will give an error after a few eof reads
506
		 * however, we cannot tell the difference
507
		 * between a zero-length read and an interrupt
508
		 * on the processes writing to us,
509
		 * so we wait for the error
510
		 */
511
		n = read9pmsg(mfd[0], mdata, sizeof mdata);
512
		if(n==0)
513
			continue;
514
		if(n < 0){
515
			if(buf[0]=='\0')
516
				errstr(buf, sizeof buf);
517
			continue;
518
		}
519
		nerr = 0;
520
		buf[0] = '\0';
521
		if(convM2S(mdata, n, &rhdr) != n)
522
			error("convert error in convM2S");
523
 
524
		if(verbose)
525
			fprint(2, "tapefs: <=%F\n", &rhdr);/**/
526
 
527
		thdr.data = (char*)mdata + IOHDRSZ;
528
		thdr.stat = mdata + IOHDRSZ;
529
		if(!fcalls[rhdr.type])
530
			err = "bad fcall type";
531
		else
532
			err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
533
		if(err){
534
			thdr.type = Rerror;
535
			thdr.ename = err;
536
		}else{
537
			thdr.type = rhdr.type + 1;
538
			thdr.fid = rhdr.fid;
539
		}
540
		thdr.tag = rhdr.tag;
541
		n = convS2M(&thdr, mdata, messagesize);
542
		if(n <= 0)
543
			error("convert error in convS2M");
544
		if(verbose)
545
			fprint(2, "tapefs: =>%F\n", &thdr);/**/
546
		if(write(mfd[1], mdata, n) != n)
547
			error("mount write");
548
	}
549
	if(buf[0]=='\0' || strstr(buf, "hungup"))
550
		exits("");
551
	fprint(2, "%s: mount read: %s\n", argv0, buf);
552
	exits(buf);
553
}
554
 
555
int
556
perm(int p)
557
{
558
	if(p==Pwrite)
559
		return 0;
560
	return 1;
561
}
562
 
563
void
564
error(char *s)
565
{
566
	fprint(2, "%s: %s: ", argv0, s);
567
	perror("");
568
	exits(s);
569
}
570
 
571
char*
572
estrdup(char *s)
573
{
574
	char *t;
575
 
576
	t = emalloc(strlen(s)+1);
577
	strcpy(t, s);
578
	return t;
579
}
580
 
581
void *
582
emalloc(ulong n)
583
{
584
	void *p;
585
	p = mallocz(n, 1);
586
	if(!p)
587
		error("out of memory");
588
	return p;
589
}
590
 
591
void *
592
erealloc(void *p, ulong n)
593
{
594
	p = realloc(p, n);
595
	if(!p)
596
		error("out of memory");
597
	return p;
598
}
599
 
600
void
601
usage(void)
602
{
603
	fprint(2, "usage: %s [-s] [-m mountpoint]\n", argv0);
604
	exits("usage");
605
}